From a16d9a0408c63ab278c660885ecda47dcce993dd Mon Sep 17 00:00:00 2001 From: peppece Date: Thu, 28 May 2020 21:32:38 +0200 Subject: [PATCH 1/9] [WIP] Implement subroutine opcodes --- docs/contributing.rst | 10 ++++- eth/abc.py | 15 +++++++ eth/vm/computation.py | 15 +++++++ eth/vm/forks/berlin/opcodes.py | 34 +++++++++++++++ eth/vm/logic/flow.py | 39 +++++++++++++++++ eth/vm/mnemonics.py | 6 +++ eth/vm/opcode_values.py | 8 ++++ eth/vm/rstack.py | 68 ++++++++++++++++++++++++++++++ tests/core/opcodes/test_opcodes.py | 59 ++++++++++++++++++++++++++ 9 files changed, 253 insertions(+), 1 deletion(-) create mode 100644 eth/vm/rstack.py diff --git a/docs/contributing.rst b/docs/contributing.rst index 115a32665e..4368b98d43 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -6,7 +6,15 @@ Thank you for your interest in contributing! We welcome all contributions no mat Setting the stage ~~~~~~~~~~~~~~~~~ -First we need to clone the Py-EVM repository. Py-EVM depends on a submodule of the common tests across all clients, so we need to clone the repo with the ``--recursive`` flag. Example: +**Only on macOS**: if it is the first time you install Py-EVM, you will need to install LevelDB with brew before taking the following steps: + +.. code:: sh + + brew install python3 LevelDB + + + +We need to clone the Py-EVM repository. Py-EVM depends on a submodule of the common tests across all clients, so we need to clone the repo with the ``--recursive`` flag. Example: .. code:: sh diff --git a/eth/abc.py b/eth/abc.py index ff08ec0792..c5535d3128 100644 --- a/eth/abc.py +++ b/eth/abc.py @@ -1655,6 +1655,21 @@ def stack_dup(self, position: int) -> None: """ ... + # + # Return Stack Managemement + # + @abstractmethod + def rstack_push_int(self) -> Callable[[int], None]: + """ + Push integer onto the return stack. + """ + + @abstractmethod + def rstack_pop1_int(self) -> Callable[[int], None]: + """ + Pop integer off the return stack and return it. + """ + # # Computation result # diff --git a/eth/vm/computation.py b/eth/vm/computation.py index 5b601591fb..fbfcfa7b4c 100644 --- a/eth/vm/computation.py +++ b/eth/vm/computation.py @@ -71,6 +71,9 @@ from eth.vm.stack import ( Stack, ) +from eth.vm.rstack import ( + RStack, +) def NO_RESULT(computation: ComputationAPI) -> None: @@ -140,6 +143,7 @@ def __init__(self, self._memory = Memory() self._stack = Stack() + self._rstack = RStack() self._gas_meter = self.get_gas_meter() self.children = [] @@ -321,6 +325,17 @@ def stack_push_int(self) -> Callable[[int], None]: def stack_push_bytes(self) -> Callable[[bytes], None]: return self._stack.push_bytes + # + # Return Stack Management + # + @cached_property + def rstack_push_int(self) -> Callable[[int], None]: + return self._rstack.push_int + + @cached_property + def rstack_pop1_int(self) -> Callable[[], int]: + return self._rstack.pop1_int + # # Computation result # diff --git a/eth/vm/forks/berlin/opcodes.py b/eth/vm/forks/berlin/opcodes.py index 9ea87cbd99..a1c3263441 100644 --- a/eth/vm/forks/berlin/opcodes.py +++ b/eth/vm/forks/berlin/opcodes.py @@ -17,3 +17,37 @@ copy.deepcopy(MUIR_GLACIER_OPCODES), UPDATED_OPCODES, ) +import copy + +from eth_utils.toolz import merge + +from eth import constants +from eth.vm import ( + mnemonics, + opcode_values, +) +from eth.vm.opcode import as_opcode +from eth.vm.logic import flow + +UPDATED_OPCODES = { + opcode_values.BEGINSUB: as_opcode( + logic_fn=flow.beginsub, + mnemonic=mnemonics.BEGINSUB, + gas_cost=constants.GAS_BASE, + ), + opcode_values.JUMPSUB: as_opcode( + logic_fn=flow.jumpsub, + mnemonic=mnemonics.JUMPSUB, + gas_cost=constants.GAS_HIGH, + ), + opcode_values.RETURNSUB: as_opcode( + logic_fn=flow.returnsub, + mnemonic=mnemonics.RETURNSUB, + gas_cost=constants.GAS_LOW, + ), +} + +BERLIN_OPCODES = merge( + copy.deepcopy(MUIR_GLACIER_OPCODES), + UPDATED_OPCODES, +) diff --git a/eth/vm/logic/flow.py b/eth/vm/logic/flow.py index 47fc7a15ad..96a149630e 100644 --- a/eth/vm/logic/flow.py +++ b/eth/vm/logic/flow.py @@ -1,12 +1,15 @@ from eth.exceptions import ( InvalidJumpDestination, InvalidInstruction, + OutOfGas, Halt, + InsufficientStack, ) from eth.vm.computation import BaseComputation from eth.vm.opcode_values import ( JUMPDEST, + BEGINSUB, ) @@ -57,3 +60,39 @@ def gas(computation: BaseComputation) -> None: gas_remaining = computation.get_gas_remaining() computation.stack_push_int(gas_remaining) + + +def beginsub(computation: BaseComputation) -> None: + raise OutOfGas("Error: at pc={}, op=BEGINSUB: invalid subroutine entry") + + +def jumpsub(computation: BaseComputation) -> None: + sub_loc = computation.stack_pop1_int() + code_range_length = computation.code.__len__() + + if sub_loc >= code_range_length: + raise InvalidJumpDestination( + "Error: at pc={}, op=JUMPSUB: invalid jump destination".format( + computation.code.program_counter) + ) + + if computation.code.is_valid_opcode(sub_loc): + + sub_op = computation.code[sub_loc] + + if sub_op == BEGINSUB: + temp = computation.code.program_counter + computation.code.program_counter = sub_loc + 1 + computation.rstack_push_int(temp) + + +def returnsub(computation: BaseComputation) -> None: + try: + ret_loc = computation.rstack_pop1_int() + except InsufficientStack: + raise InsufficientStack( + "Error: at pc={}, op=RETURNSUB: invalid retsub".format( + computation.code.program_counter) + ) + + computation.code.program_counter = ret_loc diff --git a/eth/vm/mnemonics.py b/eth/vm/mnemonics.py index 4d83de24a1..88361d550c 100644 --- a/eth/vm/mnemonics.py +++ b/eth/vm/mnemonics.py @@ -162,6 +162,12 @@ LOG3 = 'LOG3' LOG4 = 'LOG4' # +# Subroutines +# +BEGINSUB = 'BEGINSUB' +JUMPSUB = 'JUMPSUB' +RETURNSUB = 'RETURNSUB' +# # System # CREATE = 'CREATE' diff --git a/eth/vm/opcode_values.py b/eth/vm/opcode_values.py index 2845e7d4d7..26fc77d411 100644 --- a/eth/vm/opcode_values.py +++ b/eth/vm/opcode_values.py @@ -93,6 +93,14 @@ JUMPDEST = 0x5b +# +# Subroutines +# +BEGINSUB = 0x5c +RETURNSUB = 0x5d +JUMPSUB = 0x5e + + # # Push Operations # diff --git a/eth/vm/rstack.py b/eth/vm/rstack.py new file mode 100644 index 0000000000..3316e3dffe --- /dev/null +++ b/eth/vm/rstack.py @@ -0,0 +1,68 @@ +from typing import ( + List, + Tuple, + Union, +) + +from eth.exceptions import ( + InsufficientStack, + FullStack, +) + +from eth.validation import ( + validate_stack_int, +) + +from eth_utils import ( + big_endian_to_int, + ValidationError, +) + +""" +This module simply implements for the return stack the exact same design used for the data stack. +As this stack must simply push_int or pop1_int any time a subroutine is accessed or left, only +those two functions are provided. +For the same reason, the class RStack doesn't inherit from the abc StackAPI, as it would require +to implement all the abstract methods defined. +""" + + +class RStack: + """ + VM Return Stack + """ + + __slots__ = ['values', '_append', '_pop_typed', '__len__'] + + def __init__(self) -> None: + values: List[Tuple[type, Union[int, bytes]]] = [] + self.values = values + self._append = values.append + self._pop_typed = values.pop + self.__len__ = values.__len__ + + def push_int(self, value: int) -> None: + if len(self.values) > 1023: + raise FullStack('Stack limit reached') + + validate_stack_int(value) + + self._append((int, value)) + + def pop1_int(self) -> int: + # + # Note: This function is optimized for speed over readability. + # + if not self.values: + raise InsufficientStack("Wanted 1 stack item as int, had none") + else: + item_type, popped = self._pop_typed() + if item_type is int: + return popped # type: ignore + elif item_type is bytes: + return big_endian_to_int(popped) # type: ignore + else: + raise ValidationError( + "Stack must always be bytes or int, " + f"got {item_type!r} type" + ) diff --git a/tests/core/opcodes/test_opcodes.py b/tests/core/opcodes/test_opcodes.py index aa9ce10adf..50b4037288 100644 --- a/tests/core/opcodes/test_opcodes.py +++ b/tests/core/opcodes/test_opcodes.py @@ -1439,3 +1439,62 @@ def test_blake2b_f_compression(vm_class, input_hex, output_hex, expect_exception comp.raise_if_error() result = comp.output assert result.hex() == output_hex + + +@pytest.mark.parametrize( + 'vm_class, code, expect_gas_used', + ( + ( + BerlinVM, + '0x60045e005c5d', + 18, + ), + ( + BerlinVM, + '0x6800000000000000000c5e005c60115e5d5c5d', + 36, + ), + ( + BerlinVM, + '0x6005565c5d5b60035e', + 30, + ), + ) +) +def test_jumpsub(vm_class, code, expect_gas_used): + computation = setup_computation(vm_class, CANONICAL_ADDRESS_B, decode_hex(code)) + comp = computation.apply_message( + computation.state, + computation.msg, + computation.transaction_context, + ) + assert comp.is_success + assert comp.get_gas_used() == expect_gas_used + + +@pytest.mark.xfail(reason="invalid subroutines") +@pytest.mark.parametrize( + 'vm_class, code', + ( + ( + BerlinVM, + '0x5d5858', + ), + ( + BerlinVM, + '0x6801000000000000000c5e005c60115e5d5c5d', + ), + ( + BerlinVM, + '0x5c5d00', + ), + ) +) +def test_failing_jumpsub(vm_class, code): + computation = setup_computation(vm_class, CANONICAL_ADDRESS_B, decode_hex(code)) + comp = computation.apply_message( + computation.state, + computation.msg, + computation.transaction_context, + ) + assert comp.is_success From de0efa5225878e8dea911810e904568bce0281ca Mon Sep 17 00:00:00 2001 From: Giuseppe Cerami Date: Tue, 3 Nov 2020 18:11:18 +0100 Subject: [PATCH 2/9] [WIP] Implement subroutine opcodes --- docs/contributing.rst | 9 ++------- docs/guides/quickstart.rst | 4 ++-- eth/vm/forks/berlin/__init__.py | 2 +- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/docs/contributing.rst b/docs/contributing.rst index 4368b98d43..8ffe99d4ef 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -6,13 +6,8 @@ Thank you for your interest in contributing! We welcome all contributions no mat Setting the stage ~~~~~~~~~~~~~~~~~ -**Only on macOS**: if it is the first time you install Py-EVM, you will need to install LevelDB with brew before taking the following steps: - -.. code:: sh - - brew install python3 LevelDB - - +.. note:: + If it is the first time you install py-evm on macOS, check https://py-evm.readthedocs.io/en/latest/guides/quickstart.html#installing-on-macos We need to clone the Py-EVM repository. Py-EVM depends on a submodule of the common tests across all clients, so we need to clone the repo with the ``--recursive`` flag. Example: diff --git a/docs/guides/quickstart.rst b/docs/guides/quickstart.rst index 5f9319e05d..8c42deb851 100644 --- a/docs/guides/quickstart.rst +++ b/docs/guides/quickstart.rst @@ -37,11 +37,11 @@ Finally, we can install the ``py-evm`` package via pip. Installing on macOS ------------------- -First, install Python 3 with brew: +First, install Python 3 and LevelDB with brew: .. code:: sh - brew install python3 + brew install python3 leveldb .. note:: .. include:: /fragments/virtualenv_explainer.rst diff --git a/eth/vm/forks/berlin/__init__.py b/eth/vm/forks/berlin/__init__.py index bd750ee05e..34ccd00ca4 100644 --- a/eth/vm/forks/berlin/__init__.py +++ b/eth/vm/forks/berlin/__init__.py @@ -28,4 +28,4 @@ class BerlinVM(MuirGlacierVM): # Methods create_header_from_parent = staticmethod(create_berlin_header_from_parent) # type: ignore compute_difficulty = staticmethod(compute_berlin_difficulty) # type: ignore - configure_header = configure_berlin_header + configure_header = configure_berlin_header \ No newline at end of file From b5d98ab23162e39a68a40744aae329540a33a1ca Mon Sep 17 00:00:00 2001 From: Giuseppe Cerami Date: Tue, 3 Nov 2020 18:11:18 +0100 Subject: [PATCH 3/9] [WIP] Implement subroutine opcodes --- eth/vm/forks/berlin/__init__.py | 2 +- eth/vm/forks/berlin/opcodes.py | 18 ++++++++---------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/eth/vm/forks/berlin/__init__.py b/eth/vm/forks/berlin/__init__.py index 34ccd00ca4..bd750ee05e 100644 --- a/eth/vm/forks/berlin/__init__.py +++ b/eth/vm/forks/berlin/__init__.py @@ -28,4 +28,4 @@ class BerlinVM(MuirGlacierVM): # Methods create_header_from_parent = staticmethod(create_berlin_header_from_parent) # type: ignore compute_difficulty = staticmethod(compute_berlin_difficulty) # type: ignore - configure_header = configure_berlin_header \ No newline at end of file + configure_header = configure_berlin_header diff --git a/eth/vm/forks/berlin/opcodes.py b/eth/vm/forks/berlin/opcodes.py index a1c3263441..92bf3f8028 100644 --- a/eth/vm/forks/berlin/opcodes.py +++ b/eth/vm/forks/berlin/opcodes.py @@ -8,6 +8,14 @@ ) from eth.vm.opcode import Opcode +from eth import constants + +from eth.vm import ( + mnemonics, + opcode_values, +) +from eth.vm.opcode import as_opcode +from eth.vm.logic import flow UPDATED_OPCODES: Dict[int, Opcode] = { # New opcodes @@ -17,17 +25,7 @@ copy.deepcopy(MUIR_GLACIER_OPCODES), UPDATED_OPCODES, ) -import copy -from eth_utils.toolz import merge - -from eth import constants -from eth.vm import ( - mnemonics, - opcode_values, -) -from eth.vm.opcode import as_opcode -from eth.vm.logic import flow UPDATED_OPCODES = { opcode_values.BEGINSUB: as_opcode( From ad402ca3fabd77fbcec0990189c7a04a92da0b96 Mon Sep 17 00:00:00 2001 From: Giuseppe Cerami Date: Tue, 3 Nov 2020 18:11:18 +0100 Subject: [PATCH 4/9] [WIP] Implement subroutine opcodes --- eth/exceptions.py | 4 ++-- eth/vm/forks/__init__.py | 2 +- eth/vm/logic/flow.py | 18 ++++++++++++++---- tests/core/opcodes/test_opcodes.py | 14 ++++++++++---- 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/eth/exceptions.py b/eth/exceptions.py index 28de8bd6d4..e82f663c62 100644 --- a/eth/exceptions.py +++ b/eth/exceptions.py @@ -117,7 +117,7 @@ class OutOfGas(VMError): class InsufficientStack(VMError): """ - Raised when the stack is empty. + Raised when the stack or the return stack is empty. """ pass @@ -131,7 +131,7 @@ class FullStack(VMError): class InvalidJumpDestination(VMError): """ - Raised when the jump destination for a JUMPDEST operation is invalid. + Raised when the jump destination for a JUMPDEST or JUMPSUB operation is invalid. """ pass diff --git a/eth/vm/forks/__init__.py b/eth/vm/forks/__init__.py index ccce67561f..3f4e319bf6 100644 --- a/eth/vm/forks/__init__.py +++ b/eth/vm/forks/__init__.py @@ -7,7 +7,7 @@ from .homestead import ( # noqa: F401 HomesteadVM, ) -from .spurious_dragon import ( # noqa: F401 +frxom .spurious_dragon import ( # noqa: F401 SpuriousDragonVM, ) from .byzantium import ( # noqa: F401 diff --git a/eth/vm/logic/flow.py b/eth/vm/logic/flow.py index 96a149630e..0a708ecd67 100644 --- a/eth/vm/logic/flow.py +++ b/eth/vm/logic/flow.py @@ -63,17 +63,20 @@ def gas(computation: BaseComputation) -> None: def beginsub(computation: BaseComputation) -> None: - raise OutOfGas("Error: at pc={}, op=BEGINSUB: invalid subroutine entry") + raise OutOfGas("Error: at pc={}, op=BEGINSUB: invalid subroutine entry".format( + computation.code.program_counter) + ) def jumpsub(computation: BaseComputation) -> None: sub_loc = computation.stack_pop1_int() - code_range_length = computation.code.__len__() + code_range_length = len(computation.code) if sub_loc >= code_range_length: raise InvalidJumpDestination( - "Error: at pc={}, op=JUMPSUB: invalid jump destination".format( - computation.code.program_counter) + "Error: at pc={}, code_length={}, op=JUMPSUB: invalid jump destination".format( + computation.code.program_counter, + code_range_length) ) if computation.code.is_valid_opcode(sub_loc): @@ -84,6 +87,13 @@ def jumpsub(computation: BaseComputation) -> None: temp = computation.code.program_counter computation.code.program_counter = sub_loc + 1 computation.rstack_push_int(temp) + + else: + raise InvalidJumpDestination( + "Error: at pc={}, code_length={}, op=JUMPSUB: invalid jump destination".format( + computation.code.program_counter, + code_range_length) + ) def returnsub(computation: BaseComputation) -> None: diff --git a/tests/core/opcodes/test_opcodes.py b/tests/core/opcodes/test_opcodes.py index 50b4037288..8e908c1599 100644 --- a/tests/core/opcodes/test_opcodes.py +++ b/tests/core/opcodes/test_opcodes.py @@ -25,6 +25,9 @@ from eth.exceptions import ( InvalidInstruction, VMError, + InvalidJumpDestination, + InsufficientStack, + OutOfGas, ) from eth.rlp.headers import ( BlockHeader, @@ -1472,29 +1475,32 @@ def test_jumpsub(vm_class, code, expect_gas_used): assert comp.get_gas_used() == expect_gas_used -@pytest.mark.xfail(reason="invalid subroutines") @pytest.mark.parametrize( - 'vm_class, code', + 'vm_class, code, expected_exception', ( ( BerlinVM, '0x5d5858', + InsufficientStack, ), ( BerlinVM, '0x6801000000000000000c5e005c60115e5d5c5d', + InvalidJumpDestination, ), ( BerlinVM, '0x5c5d00', + OutOfGas, ), ) ) -def test_failing_jumpsub(vm_class, code): +def test_failing_jumpsub(vm_class, code, expected_exception): computation = setup_computation(vm_class, CANONICAL_ADDRESS_B, decode_hex(code)) comp = computation.apply_message( computation.state, computation.msg, computation.transaction_context, ) - assert comp.is_success + with pytest.raises(expected_exception): + comp.raise_if_error() From d2e0e4b89f95f6ee4a76c4e80ef4408b8fb37c19 Mon Sep 17 00:00:00 2001 From: Giuseppe Cerami Date: Tue, 3 Nov 2020 18:11:18 +0100 Subject: [PATCH 5/9] [WIP] Implement subroutine opcodes --- eth/vm/forks/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/vm/forks/__init__.py b/eth/vm/forks/__init__.py index 3f4e319bf6..ccce67561f 100644 --- a/eth/vm/forks/__init__.py +++ b/eth/vm/forks/__init__.py @@ -7,7 +7,7 @@ from .homestead import ( # noqa: F401 HomesteadVM, ) -frxom .spurious_dragon import ( # noqa: F401 +from .spurious_dragon import ( # noqa: F401 SpuriousDragonVM, ) from .byzantium import ( # noqa: F401 From 279aa2637ab88a93b78cdab3b8cf809eb9402b6d Mon Sep 17 00:00:00 2001 From: Giuseppe Cerami Date: Tue, 3 Nov 2020 18:11:18 +0100 Subject: [PATCH 6/9] [WIP] Implement subroutine opcodes --- eth/vm/logic/flow.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/eth/vm/logic/flow.py b/eth/vm/logic/flow.py index 0a708ecd67..83e775eac1 100644 --- a/eth/vm/logic/flow.py +++ b/eth/vm/logic/flow.py @@ -87,13 +87,13 @@ def jumpsub(computation: BaseComputation) -> None: temp = computation.code.program_counter computation.code.program_counter = sub_loc + 1 computation.rstack_push_int(temp) - + else: raise InvalidJumpDestination( - "Error: at pc={}, code_length={}, op=JUMPSUB: invalid jump destination".format( - computation.code.program_counter, - code_range_length) - ) + "Error: at pc={}, code_length={}, op=JUMPSUB: invalid jump destination".format( + computation.code.program_counter, + code_range_length) + ) def returnsub(computation: BaseComputation) -> None: From 30ed261a53397e1475506d4546744485f888a56e Mon Sep 17 00:00:00 2001 From: Giuseppe Cerami Date: Tue, 3 Nov 2020 18:11:18 +0100 Subject: [PATCH 7/9] [WIP] Implement subroutine opcodes --- tests/core/opcodes/test_opcodes.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/core/opcodes/test_opcodes.py b/tests/core/opcodes/test_opcodes.py index 8e908c1599..9d7f373a06 100644 --- a/tests/core/opcodes/test_opcodes.py +++ b/tests/core/opcodes/test_opcodes.py @@ -1493,6 +1493,15 @@ def test_jumpsub(vm_class, code, expect_gas_used): '0x5c5d00', OutOfGas, ), + ( #tests if the opcode raises error when trying to jump to BEGINSUB into pushdata + BerlinVM, + '0x60055e61005c58', + InvalidJumpDestination, + ), + ( #tests if the opcode raises error when trying to jump to an opcode other than BEGINGSUB + BerlinVM, + '0x6100055e0058' + ) ) ) def test_failing_jumpsub(vm_class, code, expected_exception): From 730d4bf000c827c06ce59f9a98c15edc94bc6835 Mon Sep 17 00:00:00 2001 From: Giuseppe Cerami Date: Tue, 3 Nov 2020 18:11:18 +0100 Subject: [PATCH 8/9] [WIP] Implement subroutine opcodes --- tests/core/opcodes/test_opcodes.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/core/opcodes/test_opcodes.py b/tests/core/opcodes/test_opcodes.py index 9d7f373a06..ab08e4dfef 100644 --- a/tests/core/opcodes/test_opcodes.py +++ b/tests/core/opcodes/test_opcodes.py @@ -1500,7 +1500,8 @@ def test_jumpsub(vm_class, code, expect_gas_used): ), ( #tests if the opcode raises error when trying to jump to an opcode other than BEGINGSUB BerlinVM, - '0x6100055e0058' + '0x6100055e0058', + InvalidJumpDestination, ) ) ) From c1647462cd570079d70689a516c33cd4197e99bd Mon Sep 17 00:00:00 2001 From: Giuseppe Cerami Date: Tue, 3 Nov 2020 18:11:18 +0100 Subject: [PATCH 9/9] [WIP] Implement subroutine opcodes --- tests/core/opcodes/test_opcodes.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/core/opcodes/test_opcodes.py b/tests/core/opcodes/test_opcodes.py index ab08e4dfef..c63ef292ec 100644 --- a/tests/core/opcodes/test_opcodes.py +++ b/tests/core/opcodes/test_opcodes.py @@ -1493,12 +1493,12 @@ def test_jumpsub(vm_class, code, expect_gas_used): '0x5c5d00', OutOfGas, ), - ( #tests if the opcode raises error when trying to jump to BEGINSUB into pushdata + ( # tests if the opcode raises error when trying to jump to BEGINSUB into pushdata BerlinVM, '0x60055e61005c58', InvalidJumpDestination, ), - ( #tests if the opcode raises error when trying to jump to an opcode other than BEGINGSUB + ( # tests if the opcode raises error when trying to jump to an opcode other than BEGINGSUB BerlinVM, '0x6100055e0058', InvalidJumpDestination,