Skip to content

Commit

Permalink
update to latest test releases + fixes
Browse files Browse the repository at this point in the history
This commit updates to the latest test releases and fixes some minor bugs exposed by the increased coverage.
In particular, the bugs related to faulty return flag in the type section are fixed. Any code section that has
RETF instruction or has a JUMPF to a returning section is considered a returning section. Otherwise, the code section
is considered non-returning. The output in the type section should reflect this behaviour. If not, the container is
invalid
  • Loading branch information
gurukamath committed Sep 25, 2024
1 parent 9d8c80e commit b6f5a85
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 8 deletions.
1 change: 1 addition & 0 deletions src/ethereum/prague/vm/eof/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ class Validator:
current_index: Uint
current_code: bytes
current_pc: Uint
is_current_section_returning: bool
has_return_contract: bool
has_stop: bool
has_return: bool
Expand Down
47 changes: 45 additions & 2 deletions src/ethereum/prague/vm/eof/instructions_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,8 +249,11 @@ def validate_jumpf(validator: Validator) -> None:
current_outputs = current_section_type[1]
target_outputs = target_section_type[1]

if target_outputs != 0x80 and target_outputs > current_outputs:
raise InvalidEof("Invalid stack height")
if target_outputs != 0x80:
if target_outputs > current_outputs:
raise InvalidEof("Invalid stack height")
validator.is_current_section_returning = True

reached_sections = validator.reached_code_sections[validator.current_index]
reached_sections.add(target_index)

Expand Down Expand Up @@ -562,6 +565,45 @@ def validate_return(validator: Validator) -> None:
)


def validate_retf(validator: Validator) -> None:
"""
Validate the RETF instructions.
Parameters
----------
validator : `Validator`
The current validator instance.
"""
code = validator.current_code
position = Uint(validator.current_pc)
counter = validator.current_pc + 1
current_metadata = validator.sections.get(validator.current_index, {})
opcode = map_int_to_op(code[position], EofVersion.EOF1)
index = validator.current_index
eof_meta = validator.eof.metadata

section_type = eof_meta.type_section_contents[index]
outputs = section_type[1]
if outputs == 0x80:
raise InvalidEof("RETF in non-returning section")

validator.is_current_section_returning = True

# Successor instruction positions
relative_offsets: List[int] = []

# Update Instruction Metadata
validator.current_pc = counter
current_metadata[position] = InstructionMetadata(
opcode=opcode,
pc_post_instruction=validator.current_pc,
relative_offsets=relative_offsets,
target_index=None,
container_index=None,
stack_height=None,
)


def validate_other_terminating_instructions(validator: Validator) -> None:
"""
Validate other terminating instructions.
Expand Down Expand Up @@ -668,6 +710,7 @@ def validate_other_instructions(validator: Validator) -> None:
Ops.RETURNCONTRACT: validate_returncontract,
Ops.STOP: validate_stop,
Ops.RETURN: validate_return,
Ops.RETF: validate_retf,
}


Expand Down
11 changes: 11 additions & 0 deletions src/ethereum/prague/vm/eof/validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,8 +159,16 @@ def validate_code_section(validator: Validator) -> None:
code_index = validator.current_index
section_type = validator.eof.metadata.type_section_contents[code_index]
section_inputs = section_type[0]
section_outputs = section_type[1]
section_max_stack_height = Uint.from_be_bytes(section_type[2:])

# If the return flag from the section type does not agree with
# the instructions in the code.
if (
section_outputs != 0x80 and not validator.is_current_section_returning
) or (section_outputs == 0x80 and validator.is_current_section_returning):
raise InvalidEof(f"Invalid return flag in section {code_index}")

computed_maximum_stack_height = 0
for index, position in enumerate(valid_opcode_positions):
validator.current_pc = position
Expand Down Expand Up @@ -249,6 +257,7 @@ def validate_eof_code(validator: Validator) -> None:
validator.current_index = Uint(code_index)
validator.current_code = code
validator.current_pc = Uint(0)
validator.is_current_section_returning = False
validator.sections[validator.current_index] = {}
validate_code_section(validator)

Expand Down Expand Up @@ -340,6 +349,7 @@ def validate_eof_container(
current_index=Uint(0),
current_code=metadata.code_section_contents[0],
current_pc=Uint(0),
is_current_section_returning=False,
sections={},
has_return_contract=False,
has_stop=False,
Expand Down Expand Up @@ -396,6 +406,7 @@ def parse_create_tx_call_data(data: bytes) -> Tuple[Eof, bytes]:
current_index=Uint(0),
current_code=eof.metadata.code_section_contents[0],
current_pc=Uint(0),
is_current_section_returning=False,
has_return_contract=False,
has_stop=False,
has_return=False,
Expand Down
2 changes: 1 addition & 1 deletion tests/helpers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
},
"latest_fork_tests": {
"url": "https://github.com/gurukamath/latest_fork_tests.git",
"commit_hash": "1a9b58e",
"commit_hash": "b5c73d5",
"fixture_path": "tests/fixtures/latest_fork_tests",
},
}
8 changes: 5 additions & 3 deletions tests/prague/test_evm_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@
"tests/fixtures/latest_fork_tests/state_tests/prague/eip2537_bls_12_381_precompiles",
"tests/fixtures/latest_fork_tests/state_tests/prague/eip7702_set_code_tx",
"tests/fixtures/latest_fork_tests/state_tests/prague/eip7692_eof_v1",
"tests/fixtures/ethereum_tests/EIPTests/StateTests/stEOF",
# TODO: The following evmone tests for EOF are currently disabled since
# some of the fixtures are malformed. They will be enabled once the
# new fixtures are available.
# "tests/fixtures/latest_fork_tests/evmone_tests/state_tests",
)

IGNORE_TESTS = (
Expand All @@ -49,9 +54,6 @@
"tests/prague/eip7702_set_code_tx/test_set_code_txs.py::test_invalid_tx_invalid_auth_signature[fork_Prague-state_test-v_0,r_1,s_2**256-1]",
"tests/fixtures/latest_fork_tests/state_tests/prague/eip7692_eof_v1",
"tests/fixtures/ethereum_tests/EIPTests/StateTests/stEOF",
# # TODO: Run evmone tests after they have been fixed
# # There are currently some malformed fixtures in the evmone tests
# "tests/fixtures/latest_fork_tests/evmone_tests/state_tests",
)


Expand Down
3 changes: 1 addition & 2 deletions tests/prague/test_state_transition.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,7 @@
"tests/fixtures/latest_fork_tests/blockchain_tests/prague/eip2537_bls_12_381_precompiles",
"tests/fixtures/latest_fork_tests/blockchain_tests/prague/eip2935_historical_block_hashes_from_state",
"tests/fixtures/latest_fork_tests/blockchain_tests/prague/eip7702_set_code_tx",
# TODO: Current test fixtures don't support EOF along with other
# EIPs. This will be fixed in the future.
"tests/fixtures/latest_fork_tests/blockchain_tests/prague/eip7692_eof_v1",
)


Expand Down

0 comments on commit b6f5a85

Please sign in to comment.