diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 40dcb16889..3b4d747abb 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -26,6 +26,7 @@ Test fixtures for use by clients are available for each release on the [Github r - ✨ Convert a few eip1153 tests from ethereum/tests repo into .py ([#440](https://github.com/ethereum/execution-spec-tests/pull/440)). - ✨ Add tests for [EIP-7480: EOF - Data section access instructions](https://eips.ethereum.org/EIPS/eip-7480) ([#518](https://github.com/ethereum/execution-spec-tests/pull/518), [#664](https://github.com/ethereum/execution-spec-tests/pull/664)). - ✨ Add tests for subcontainer kind validation from [EIP-7620: EOF Contract Creation](https://eips.ethereum.org/EIPS/eip-7620) for the cases with deeply nested containers and non-first code sections ([#676](https://github.com/ethereum/execution-spec-tests/pull/676)). +- ✨ Add tests for runtime stack overflow at CALLF instruction from [EIP-4750: EOF - Functions](https://eips.ethereum.org/EIPS/eip-4750) for the cases with deeply nested containers and non-first code sections ([#678](https://github.com/ethereum/execution-spec-tests/pull/678)). ### 🛠️ Framework diff --git a/tests/prague/eip7692_eof_v1/eip4750_functions/__init__.py b/tests/prague/eip7692_eof_v1/eip4750_functions/__init__.py new file mode 100644 index 0000000000..ba2edc4b15 --- /dev/null +++ b/tests/prague/eip7692_eof_v1/eip4750_functions/__init__.py @@ -0,0 +1,3 @@ +""" +EOF tests for EIP-4750 functions +""" diff --git a/tests/prague/eip7692_eof_v1/eip4750_functions/helpers.py b/tests/prague/eip7692_eof_v1/eip4750_functions/helpers.py new file mode 100644 index 0000000000..82e0bed985 --- /dev/null +++ b/tests/prague/eip7692_eof_v1/eip4750_functions/helpers.py @@ -0,0 +1,14 @@ +""" +EOF Functions tests helpers +""" + +import itertools + +"""Storage addresses for common testing fields""" +_slot = itertools.count() +next(_slot) # don't use slot 0 +slot_code_worked = next(_slot) +slot_last_slot = next(_slot) + +"""Storage values for common testing fields""" +value_code_worked = 0x2015 diff --git a/tests/prague/eip7692_eof_v1/eip4750_functions/test_callf_execution.py b/tests/prague/eip7692_eof_v1/eip4750_functions/test_callf_execution.py new file mode 100644 index 0000000000..03760d5f95 --- /dev/null +++ b/tests/prague/eip7692_eof_v1/eip4750_functions/test_callf_execution.py @@ -0,0 +1,254 @@ +""" +EOF CALLF execution tests +""" + +import pytest + +from ethereum_test_tools import Account, EOFStateTestFiller +from ethereum_test_tools import Opcodes as Op +from ethereum_test_tools.eof.v1 import Container, Section + +from .. import EOF_FORK_NAME +from .helpers import slot_code_worked, value_code_worked + +REFERENCE_SPEC_GIT_PATH = "EIPS/eip-4750.md" +REFERENCE_SPEC_VERSION = "14400434e1199c57d912082127b1d22643788d11" + +pytestmark = pytest.mark.valid_from(EOF_FORK_NAME) + + +def test_callf_stack_size_1024( + eof_state_test: EOFStateTestFiller, +): + """Test stack reaching 1024 items in called function""" + eof_state_test( + data=Container( + sections=[ + Section.Code( + code=Op.PUSH0 * 1023 + + Op.CALLF[1] + + Op.POP * 1023 + + Op.SSTORE(slot_code_worked, value_code_worked) + + Op.RETURN(0, 0), + max_stack_height=1023, + ), + Section.Code( + Op.PUSH0 + Op.POP + Op.RETF, + code_inputs=0, + code_outputs=0, + max_stack_height=1, + ), + ], + ), + container_post=Account(storage={slot_code_worked: value_code_worked}), + ) + + +def test_callf_with_inputs_stack_size_1024( + eof_state_test: EOFStateTestFiller, +): + """Test stack reaching 1024 items in called function with inputs""" + eof_state_test( + data=Container( + sections=[ + Section.Code( + code=Op.PUSH0 * 1023 + + Op.CALLF[1] + + Op.POP * 1023 + + Op.SSTORE(slot_code_worked, value_code_worked) + + Op.RETURN(0, 0), + max_stack_height=1023, + ), + Section.Code( + Op.PUSH0 + Op.POP + Op.RETF, + code_inputs=3, + code_outputs=3, + max_stack_height=4, + ), + ], + ), + container_post=Account(storage={slot_code_worked: value_code_worked}), + ) + + +def test_callf_stack_size_1024_at_callf( + eof_state_test: EOFStateTestFiller, +): + """Test stack reaching 1024 items in called function at CALLF instruction""" + eof_state_test( + data=Container( + sections=[ + Section.Code( + code=Op.PUSH0 * 1023 + + Op.CALLF[1] + + Op.POP * 1023 + + Op.SSTORE(slot_code_worked, value_code_worked) + + Op.RETURN(0, 0), + max_stack_height=1023, + ), + Section.Code( + Op.CALLF[2] + + # stack has 1024 items + Op.POP + Op.RETF, + code_inputs=0, + code_outputs=0, + max_stack_height=1, + ), + Section.Code( + Op.PUSH0 + Op.RETF, # stack has 1024 items + code_inputs=0, + code_outputs=1, + max_stack_height=1, + ), + ], + ), + container_post=Account(storage={slot_code_worked: value_code_worked}), + ) + + +def test_callf_stack_size_1024_at_push( + eof_state_test: EOFStateTestFiller, +): + """Test stack reaching 1024 items in nested called function at PUSH0 instruction""" + eof_state_test( + data=Container( + sections=[ + Section.Code( + code=Op.PUSH0 * 1022 + + Op.CALLF[1] + + Op.POP * 1022 + + Op.SSTORE(slot_code_worked, value_code_worked) + + Op.RETURN(0, 0), + max_stack_height=1022, + ), + Section.Code( + Op.PUSH0 + + # stack has 1023 items + Op.CALLF[2] + Op.POP + Op.RETF, + code_inputs=0, + code_outputs=0, + max_stack_height=1, + ), + Section.Code( + Op.PUSH0 + + # stack has 1024 items + Op.POP + Op.RETF, + code_inputs=0, + code_outputs=0, + max_stack_height=1, + ), + ], + ), + container_post=Account(storage={slot_code_worked: value_code_worked}), + ) + + +def test_callf_stack_overflow( + eof_state_test: EOFStateTestFiller, +): + """Test stack overflowing 1024 items in called function""" + eof_state_test( + data=Container( + sections=[ + Section.Code( + code=Op.PUSH0 * 1023 + + Op.CALLF[1] + + Op.POP * 1023 + + Op.SSTORE(slot_code_worked, value_code_worked) + + Op.RETURN(0, 0), + max_stack_height=1023, + ), + Section.Code( + Op.PUSH0 + + # Stack has 1024 items + Op.CALLF[2] + Op.POP + Op.RETF, + code_inputs=0, + code_outputs=0, + max_stack_height=1, + ), + Section.Code( + Op.PUSH0 + + # Runtime stack overflow + Op.POP + Op.RETF, + code_inputs=0, + code_outputs=0, + max_stack_height=1, + ), + ], + ), + container_post=Account(storage={slot_code_worked: 0}), + ) + + +def test_callf_with_inputs_stack_size_1024_at_push( + eof_state_test: EOFStateTestFiller, +): + """Test stack reaching 1024 items in nested called function with inputs at PUSH0 instruction""" + eof_state_test( + data=Container( + sections=[ + Section.Code( + code=Op.PUSH0 * 1022 + + Op.CALLF[1] + + Op.POP * 1022 + + Op.SSTORE(slot_code_worked, value_code_worked) + + Op.RETURN(0, 0), + max_stack_height=1022, + ), + Section.Code( + Op.PUSH0 + + # Stack has 1023 items + Op.CALLF[2] + Op.POP + Op.RETF, + code_inputs=3, + code_outputs=3, + max_stack_height=4, + ), + Section.Code( + Op.PUSH0 + + # Stack has 1024 items + Op.POP + Op.RETF, + code_inputs=3, + code_outputs=3, + max_stack_height=4, + ), + ], + ), + container_post=Account(storage={slot_code_worked: value_code_worked}), + ) + + +def test_callf_with_inputs_stack_overflow( + eof_state_test: EOFStateTestFiller, +): + """Test stack overflowing 1024 items in called function with inputs""" + eof_state_test( + data=Container( + sections=[ + Section.Code( + code=Op.PUSH0 * 1023 + + Op.CALLF[1] + + Op.POP * 1023 + + Op.SSTORE(slot_code_worked, value_code_worked) + + Op.RETURN(0, 0), + max_stack_height=1023, + ), + Section.Code( + Op.PUSH0 + + # Stack has 1024 items + Op.CALLF[2] + Op.POP + Op.RETF, + code_inputs=3, + code_outputs=3, + max_stack_height=4, + ), + Section.Code( + Op.PUSH0 + + # Runtime stackoverflow + Op.POP + Op.RETF, + code_inputs=3, + code_outputs=3, + max_stack_height=4, + ), + ], + ), + container_post=Account(storage={slot_code_worked: 0}), + )