Skip to content

Commit

Permalink
feat(exceptions,specs): class to verify exception strings (#795)
Browse files Browse the repository at this point in the history
* feat(exception mapper): class to verify exception strings

* add GethExceptionMapper

* refactor exception mapper
parse expected exception lists

* integrate other t8n's exception maps

* implement None ins exception_to_message

* fix rebase

* fix tox

* add exception classes, add exception verification into state tests

* fix(specs): tests

---------

Co-authored-by: Mario Vega <[email protected]>
  • Loading branch information
winsvega and marioevz authored Oct 23, 2024
1 parent e317fd0 commit 247c312
Show file tree
Hide file tree
Showing 20 changed files with 1,163 additions and 161 deletions.
3 changes: 2 additions & 1 deletion src/ethereum_clis/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from .clis.besu import BesuTransitionTool
from .clis.ethereumjs import EthereumJSTransitionTool
from .clis.evmone import EvmOneTransitionTool
from .clis.evmone import EvmoneExceptionMapper, EvmOneTransitionTool
from .clis.execution_specs import ExecutionSpecsTransitionTool
from .clis.geth import GethTransitionTool
from .clis.nimbus import NimbusTransitionTool
Expand All @@ -20,6 +20,7 @@
"EvmOneTransitionTool",
"ExecutionSpecsTransitionTool",
"GethTransitionTool",
"EvmoneExceptionMapper",
"NimbusTransitionTool",
"Result",
"TransitionTool",
Expand Down
142 changes: 141 additions & 1 deletion src/ethereum_clis/clis/besu.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@

import requests

from ethereum_test_exceptions import (
EOFException,
ExceptionMapper,
ExceptionMessage,
TransactionException,
)
from ethereum_test_forks import Fork
from ethereum_test_types import Alloc, Environment, Transaction

Expand Down Expand Up @@ -41,7 +47,7 @@ def __init__(
binary: Optional[Path] = None,
trace: bool = False,
):
super().__init__(binary=binary, trace=trace)
super().__init__(exception_mapper=BesuExceptionMapper(), binary=binary, trace=trace)
args = [str(self.binary), "t8n", "--help"]
try:
result = subprocess.run(args, capture_output=True, text=True)
Expand Down Expand Up @@ -201,3 +207,137 @@ def is_fork_supported(self, fork: Fork) -> bool:
Returns True if the fork is supported by the tool
"""
return fork.transition_tool_name() in self.help_string


class BesuExceptionMapper(ExceptionMapper):
"""
Translate between EEST exceptions and error strings returned by nimbus.
"""

@property
def _mapping_data(self):
return [
ExceptionMessage(
TransactionException.TYPE_4_TX_CONTRACT_CREATION,
"set code transaction must not be a create transaction",
),
ExceptionMessage(
TransactionException.INSUFFICIENT_ACCOUNT_FUNDS,
"exceeds transaction sender account balance",
),
ExceptionMessage(
TransactionException.TYPE_3_TX_MAX_BLOB_GAS_ALLOWANCE_EXCEEDED,
"would exceed block maximum",
),
ExceptionMessage(
TransactionException.INSUFFICIENT_MAX_FEE_PER_BLOB_GAS,
"max fee per blob gas less than block blob gas fee",
),
ExceptionMessage(
TransactionException.INSUFFICIENT_MAX_FEE_PER_GAS,
"gasPrice is less than the current BaseFee",
),
ExceptionMessage(
TransactionException.TYPE_3_TX_PRE_FORK,
"Transaction type BLOB is invalid, accepted transaction types are [EIP1559, ACCESS_LIST, FRONTIER]", # noqa: E501
),
ExceptionMessage(
TransactionException.TYPE_3_TX_INVALID_BLOB_VERSIONED_HASH,
"Only supported hash version is 0x01, sha256 hash.",
),
# This message is the same as TYPE_3_TX_MAX_BLOB_GAS_ALLOWANCE_EXCEEDED
ExceptionMessage(
TransactionException.TYPE_3_TX_BLOB_COUNT_EXCEEDED,
"exceed block maximum",
),
ExceptionMessage(
TransactionException.TYPE_3_TX_ZERO_BLOBS,
"Blob transaction must have at least one versioned hash",
),
ExceptionMessage(
TransactionException.INTRINSIC_GAS_TOO_LOW,
"intrinsic gas too low",
),
ExceptionMessage(
TransactionException.INITCODE_SIZE_EXCEEDED,
"max initcode size exceeded",
),
# TODO EVMONE needs to differentiate when the section is missing in the header or body
ExceptionMessage(EOFException.MISSING_STOP_OPCODE, "err: no_terminating_instruction"),
ExceptionMessage(EOFException.MISSING_CODE_HEADER, "err: code_section_missing"),
ExceptionMessage(EOFException.MISSING_TYPE_HEADER, "err: type_section_missing"),
# TODO EVMONE these exceptions are too similar, this leeds to ambiguity
ExceptionMessage(EOFException.MISSING_TERMINATOR, "err: header_terminator_missing"),
ExceptionMessage(
EOFException.MISSING_HEADERS_TERMINATOR, "err: section_headers_not_terminated"
),
ExceptionMessage(EOFException.INVALID_VERSION, "err: eof_version_unknown"),
ExceptionMessage(
EOFException.INVALID_NON_RETURNING_FLAG, "err: invalid_non_returning_flag"
),
ExceptionMessage(EOFException.INVALID_MAGIC, "err: invalid_prefix"),
ExceptionMessage(
EOFException.INVALID_FIRST_SECTION_TYPE, "err: invalid_first_section_type"
),
ExceptionMessage(
EOFException.INVALID_SECTION_BODIES_SIZE, "err: invalid_section_bodies_size"
),
ExceptionMessage(
EOFException.INVALID_TYPE_SECTION_SIZE, "err: invalid_type_section_size"
),
ExceptionMessage(EOFException.INCOMPLETE_SECTION_SIZE, "err: incomplete_section_size"),
ExceptionMessage(
EOFException.INCOMPLETE_SECTION_NUMBER, "err: incomplete_section_number"
),
ExceptionMessage(EOFException.TOO_MANY_CODE_SECTIONS, "err: too_many_code_sections"),
ExceptionMessage(EOFException.ZERO_SECTION_SIZE, "err: zero_section_size"),
ExceptionMessage(EOFException.MISSING_DATA_SECTION, "err: data_section_missing"),
ExceptionMessage(EOFException.UNDEFINED_INSTRUCTION, "err: undefined_instruction"),
ExceptionMessage(
EOFException.INPUTS_OUTPUTS_NUM_ABOVE_LIMIT, "err: inputs_outputs_num_above_limit"
),
ExceptionMessage(
EOFException.UNREACHABLE_INSTRUCTIONS, "err: unreachable_instructions"
),
ExceptionMessage(
EOFException.INVALID_RJUMP_DESTINATION, "err: invalid_rjump_destination"
),
ExceptionMessage(
EOFException.UNREACHABLE_CODE_SECTIONS, "err: unreachable_code_sections"
),
ExceptionMessage(EOFException.STACK_UNDERFLOW, "err: stack_underflow"),
ExceptionMessage(
EOFException.MAX_STACK_HEIGHT_ABOVE_LIMIT, "err: max_stack_height_above_limit"
),
ExceptionMessage(
EOFException.STACK_HIGHER_THAN_OUTPUTS, "err: stack_higher_than_outputs_required"
),
ExceptionMessage(
EOFException.JUMPF_DESTINATION_INCOMPATIBLE_OUTPUTS,
"err: jumpf_destination_incompatible_outputs",
),
ExceptionMessage(
EOFException.INVALID_MAX_STACK_HEIGHT, "err: invalid_max_stack_height"
),
ExceptionMessage(EOFException.INVALID_DATALOADN_INDEX, "err: invalid_dataloadn_index"),
ExceptionMessage(EOFException.TRUNCATED_INSTRUCTION, "err: truncated_instruction"),
ExceptionMessage(
EOFException.TOPLEVEL_CONTAINER_TRUNCATED, "err: toplevel_container_truncated"
),
ExceptionMessage(EOFException.ORPHAN_SUBCONTAINER, "err: unreferenced_subcontainer"),
ExceptionMessage(
EOFException.CONTAINER_SIZE_ABOVE_LIMIT, "err: container_size_above_limit"
),
ExceptionMessage(
EOFException.INVALID_CONTAINER_SECTION_INDEX,
"err: invalid_container_section_index",
),
ExceptionMessage(
EOFException.INCOMPATIBLE_CONTAINER_KIND, "err: incompatible_container_kind"
),
ExceptionMessage(EOFException.STACK_HEIGHT_MISMATCH, "err: stack_height_mismatch"),
ExceptionMessage(EOFException.TOO_MANY_CONTAINERS, "err: too_many_container_sections"),
ExceptionMessage(
EOFException.INVALID_CODE_SECTION_INDEX, "err: invalid_code_section_index"
),
]
142 changes: 141 additions & 1 deletion src/ethereum_clis/clis/ethereumjs.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
from re import compile
from typing import Optional

from ethereum_test_exceptions import (
EOFException,
ExceptionMapper,
ExceptionMessage,
TransactionException,
)
from ethereum_test_forks import Fork

from ..transition_tool import TransitionTool
Expand All @@ -31,11 +37,145 @@ def __init__(
binary: Optional[Path] = None,
trace: bool = False,
):
super().__init__(binary=binary, trace=trace)
super().__init__(exception_mapper=EthereumJSExceptionMapper(), binary=binary, trace=trace)

def is_fork_supported(self, fork: Fork) -> bool:
"""
Returns True if the fork is supported by the tool.
Currently, EthereumJS-t8n provides no way to determine supported forks.
"""
return True


class EthereumJSExceptionMapper(ExceptionMapper):
"""
Translate between EEST exceptions and error strings returned by ethereum-js.
"""

@property
def _mapping_data(self):
return [
ExceptionMessage(
TransactionException.TYPE_4_TX_CONTRACT_CREATION,
"set code transaction must not be a create transaction",
),
ExceptionMessage(
TransactionException.INSUFFICIENT_ACCOUNT_FUNDS,
"insufficient funds for gas * price + value",
),
ExceptionMessage(
TransactionException.TYPE_3_TX_MAX_BLOB_GAS_ALLOWANCE_EXCEEDED,
"would exceed maximum allowance",
),
ExceptionMessage(
TransactionException.INSUFFICIENT_MAX_FEE_PER_BLOB_GAS,
"max fee per blob gas less than block blob gas fee",
),
ExceptionMessage(
TransactionException.INSUFFICIENT_MAX_FEE_PER_GAS,
"max fee per gas less than block base fee",
),
ExceptionMessage(
TransactionException.TYPE_3_TX_PRE_FORK,
"blob tx used but field env.ExcessBlobGas missing",
),
ExceptionMessage(
TransactionException.TYPE_3_TX_INVALID_BLOB_VERSIONED_HASH,
"has invalid hash version",
),
# This message is the same as TYPE_3_TX_MAX_BLOB_GAS_ALLOWANCE_EXCEEDED
ExceptionMessage(
TransactionException.TYPE_3_TX_BLOB_COUNT_EXCEEDED,
"exceed maximum allowance",
),
ExceptionMessage(
TransactionException.TYPE_3_TX_ZERO_BLOBS,
"blob transaction missing blob hashes",
),
ExceptionMessage(
TransactionException.INTRINSIC_GAS_TOO_LOW,
"is lower than the minimum gas limit of",
),
ExceptionMessage(
TransactionException.INITCODE_SIZE_EXCEEDED,
"max initcode size exceeded",
),
# TODO EVMONE needs to differentiate when the section is missing in the header or body
ExceptionMessage(EOFException.MISSING_STOP_OPCODE, "err: no_terminating_instruction"),
ExceptionMessage(EOFException.MISSING_CODE_HEADER, "err: code_section_missing"),
ExceptionMessage(EOFException.MISSING_TYPE_HEADER, "err: type_section_missing"),
# TODO EVMONE these exceptions are too similar, this leeds to ambiguity
ExceptionMessage(EOFException.MISSING_TERMINATOR, "err: header_terminator_missing"),
ExceptionMessage(
EOFException.MISSING_HEADERS_TERMINATOR, "err: section_headers_not_terminated"
),
ExceptionMessage(EOFException.INVALID_VERSION, "err: eof_version_unknown"),
ExceptionMessage(
EOFException.INVALID_NON_RETURNING_FLAG, "err: invalid_non_returning_flag"
),
ExceptionMessage(EOFException.INVALID_MAGIC, "err: invalid_prefix"),
ExceptionMessage(
EOFException.INVALID_FIRST_SECTION_TYPE, "err: invalid_first_section_type"
),
ExceptionMessage(
EOFException.INVALID_SECTION_BODIES_SIZE, "err: invalid_section_bodies_size"
),
ExceptionMessage(
EOFException.INVALID_TYPE_SECTION_SIZE, "err: invalid_type_section_size"
),
ExceptionMessage(EOFException.INCOMPLETE_SECTION_SIZE, "err: incomplete_section_size"),
ExceptionMessage(
EOFException.INCOMPLETE_SECTION_NUMBER, "err: incomplete_section_number"
),
ExceptionMessage(EOFException.TOO_MANY_CODE_SECTIONS, "err: too_many_code_sections"),
ExceptionMessage(EOFException.ZERO_SECTION_SIZE, "err: zero_section_size"),
ExceptionMessage(EOFException.MISSING_DATA_SECTION, "err: data_section_missing"),
ExceptionMessage(EOFException.UNDEFINED_INSTRUCTION, "err: undefined_instruction"),
ExceptionMessage(
EOFException.INPUTS_OUTPUTS_NUM_ABOVE_LIMIT, "err: inputs_outputs_num_above_limit"
),
ExceptionMessage(
EOFException.UNREACHABLE_INSTRUCTIONS, "err: unreachable_instructions"
),
ExceptionMessage(
EOFException.INVALID_RJUMP_DESTINATION, "err: invalid_rjump_destination"
),
ExceptionMessage(
EOFException.UNREACHABLE_CODE_SECTIONS, "err: unreachable_code_sections"
),
ExceptionMessage(EOFException.STACK_UNDERFLOW, "err: stack_underflow"),
ExceptionMessage(
EOFException.MAX_STACK_HEIGHT_ABOVE_LIMIT, "err: max_stack_height_above_limit"
),
ExceptionMessage(
EOFException.STACK_HIGHER_THAN_OUTPUTS, "err: stack_higher_than_outputs_required"
),
ExceptionMessage(
EOFException.JUMPF_DESTINATION_INCOMPATIBLE_OUTPUTS,
"err: jumpf_destination_incompatible_outputs",
),
ExceptionMessage(
EOFException.INVALID_MAX_STACK_HEIGHT, "err: invalid_max_stack_height"
),
ExceptionMessage(EOFException.INVALID_DATALOADN_INDEX, "err: invalid_dataloadn_index"),
ExceptionMessage(EOFException.TRUNCATED_INSTRUCTION, "err: truncated_instruction"),
ExceptionMessage(
EOFException.TOPLEVEL_CONTAINER_TRUNCATED, "err: toplevel_container_truncated"
),
ExceptionMessage(EOFException.ORPHAN_SUBCONTAINER, "err: unreferenced_subcontainer"),
ExceptionMessage(
EOFException.CONTAINER_SIZE_ABOVE_LIMIT, "err: container_size_above_limit"
),
ExceptionMessage(
EOFException.INVALID_CONTAINER_SECTION_INDEX,
"err: invalid_container_section_index",
),
ExceptionMessage(
EOFException.INCOMPATIBLE_CONTAINER_KIND, "err: incompatible_container_kind"
),
ExceptionMessage(EOFException.STACK_HEIGHT_MISMATCH, "err: stack_height_mismatch"),
ExceptionMessage(EOFException.TOO_MANY_CONTAINERS, "err: too_many_container_sections"),
ExceptionMessage(
EOFException.INVALID_CODE_SECTION_INDEX, "err: invalid_code_section_index"
),
]
Loading

0 comments on commit 247c312

Please sign in to comment.