Skip to content

Commit cb4ccde

Browse files
feat(consume): add ExceptionMapper support to the consume-engine simulator (#1416)
* fix(exceptions): UndefinedException return on new * feat(rpc,plugins/consume): Support exception mapper * fix(exceptions): Allow undefined mapper * feat(plugins/consume): Add more mappers * fix(logging): don't use newlines within log messages * refactor(exceptions,specs): ExceptionWithMessage contains a list * new(exceptions): Add `INVALID_BLOCK_HASH` exception * feat(clis): Add ethjs exceptions * feat(clis): Add geth exceptions * feat(plugins/consume): Add besu exceptions * feat(plugins/consume): Add nethermind exceptions * feat(plugins/consume): Add reth exceptions * feat(consume): add `--strict-exception-matching` parameter * more reth exceptions * refactor mappers * add ethjs exception * fix(tests): EIP-7685: Add expected exception to `test_invalid_multi_type_requests_engine` * add reth exception * fix(plugins/consume): log failure * feat(clis): Add Erigon Exception Mapper * feat(specs): Allow setting expected block exception for state tests (only affects generated block tests) * fix(tests): Add block exceltion to test_blob_type_tx_pre_fork * fix(clis): Exceptions in mappers * change(plugins/consume): Enable strict exception matching by default * fix(specs): Exception message check on strict match * docs: changelog * chore(clis): update exception mappers for TYPE_4_TX_PRE_FORK * refactor(consume): cache exception mappers in session-scoped fixture * refactor(consume): make string match more robust by applying `lower()` * feat(consume): allow disabling of strict exception checking per fork * refactor(consume/hive): create `strict_exception_matching` fixture * fix: whitelist * changelog: Add exception * changelog: Invalid versioned hashes exception * refactor(consume/engine): Better error logging * fix(clis/reth): Exception mapper * fix(clis/besu): Exception mapper * fix(clis/geth): Exception mapper * fix(clis/ethereumjs): Exception mapper * fix(clis/erigon): Exception mapper --------- Co-authored-by: danceratopz <[email protected]>
1 parent c8ec6e6 commit cb4ccde

File tree

20 files changed

+780
-261
lines changed

20 files changed

+780
-261
lines changed

docs/CHANGELOG.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,14 @@ Test fixtures for use by clients are available for each release on the [Github r
88

99
### 💥 Breaking Change
1010

11+
#### Consume engine strict exception checking
12+
13+
`consume engine` now checks exceptions returned by the execution clients in their Engine API responses, specifically in the `validationError`field of the `engine_newPayloadVX` method.
14+
15+
While not strictly a breaking change since tests will continue to run normally, failures are expected if a client modifies their exception messages.
16+
17+
This feature can be disabled by using `--disable-strict-exception-matching` for specific clients or forks.
18+
1119
### 🛠️ Framework
1220

1321
#### `fill`
@@ -19,6 +27,7 @@ Test fixtures for use by clients are available for each release on the [Github r
1927
#### `consume`
2028

2129
- 🐞 Fix fixture tarball downloading with regular, non-Github release URLS and with numerical versions in regular release specs, e.g., `[email protected]` ([#1437](https://github.com/ethereum/execution-spec-tests/pull/1437)).
30+
-`consume engine` now has strict exception mapping enabled by default ([#1416](https://github.com/ethereum/execution-spec-tests/pull/1416)).
2231

2332
#### Tools
2433

@@ -27,7 +36,10 @@ Test fixtures for use by clients are available for each release on the [Github r
2736

2837
#### Exceptions
2938

30-
- ✨ New exceptions `BlockException.SYSTEM_CONTRACT_EMPTY` and `BlockException.SYSTEM_CONTRACT_CALL_FAILED` to handle EIP updates [#9508](https://github.com/ethereum/EIPs/pull/9508) and [#9582](https://github.com/ethereum/EIPs/pull/9582) ([#1394](https://github.com/ethereum/execution-spec-tests/pull/1394)).
39+
-`BlockException.SYSTEM_CONTRACT_EMPTY`: Raised when a required system contract was not found in the state by the time it was due to execution with a system transaction call ([#1394](https://github.com/ethereum/execution-spec-tests/pull/1394)).
40+
-`BlockException.SYSTEM_CONTRACT_CALL_FAILED`: Raised when a system contract call made by a system transaction fails ([#1394](https://github.com/ethereum/execution-spec-tests/pull/1394)).
41+
-`BlockException.INVALID_BLOCK_HASH`: Raised when the calculated block hash does not match the expectation (Currently only during Engine API calls) ([#1416](https://github.com/ethereum/execution-spec-tests/pull/1416)).
42+
-`BlockException.INVALID_VERSIONED_HASHES`: Raised when a discrepancy is found between versioned hashes in the payload and the ones found in the transactions ([#1416](https://github.com/ethereum/execution-spec-tests/pull/1416)).
3143

3244
### 🧪 Test Cases
3345

@@ -37,6 +49,7 @@ Test fixtures for use by clients are available for each release on the [Github r
3749
-[EIP-7623](https://eips.ethereum.org/EIPS/eip-7623): Additionally parametrize transaction validity tests with the `to` set to an EOA account (previously only contracts) ([#1422](https://github.com/ethereum/execution-spec-tests/pull/1422)).
3850
-[EIP-7251](https://eips.ethereum.org/EIPS/eip-7251): Add EIP-7251 test cases for modified consolidations contract that allows more consolidations ([#1465](https://github.com/ethereum/execution-spec-tests/pull/1465)).
3951
-[EIP-6110](https://eips.ethereum.org/EIPS/eip-6110): Add extra deposit request edge cases, sending eth to the deposit contract while sending a deposit request ([#1467](https://github.com/ethereum/execution-spec-tests/pull/1467)).
52+
-[EIP-6110](https://eips.ethereum.org/EIPS/eip-6110): Add cases for deposit log layout and other topics (ERC-20) transfer ([#1371](https://github.com/ethereum/execution-spec-tests/pull/1371)).
4053
-[EIP-7251](https://eips.ethereum.org/EIPS/eip-7251): Remove pytest skips for consolidation request cases ([#1449](https://github.com/ethereum/execution-spec-tests/pull/1449)).
4154
-[EIP-7002](https://eips.ethereum.org/EIPS/eip-7002), [EIP-7251](https://eips.ethereum.org/EIPS/eip-7251): Add cases to verify behavior of contracts missing at fork ([#1394](https://github.com/ethereum/execution-spec-tests/pull/1394)).
4255
-[EIP-7002](https://eips.ethereum.org/EIPS/eip-7002), [EIP-7251](https://eips.ethereum.org/EIPS/eip-7251): Add cases to verify behavior of system contract errors invalidating a block ([#1394](https://github.com/ethereum/execution-spec-tests/pull/1394)).

src/ethereum_clis/clis/besu.py

Lines changed: 68 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
from ethereum_test_base_types import BlobSchedule
1515
from ethereum_test_exceptions import (
16+
BlockException,
1617
EOFException,
1718
ExceptionBase,
1819
ExceptionMapper,
@@ -212,36 +213,53 @@ class BesuExceptionMapper(ExceptionMapper):
212213
"""Translate between EEST exceptions and error strings returned by Besu."""
213214

214215
mapping_substring: ClassVar[Dict[ExceptionBase, str]] = {
215-
TransactionException.TYPE_4_TX_CONTRACT_CREATION: (
216-
"transaction code delegation transactions must have a non-empty code delegation list"
216+
TransactionException.INSUFFICIENT_MAX_FEE_PER_BLOB_GAS: (
217+
"transaction invalid tx max fee per blob gas less than block blob gas fee"
217218
),
218-
TransactionException.INSUFFICIENT_ACCOUNT_FUNDS: (
219-
"exceeds transaction sender account balance"
219+
TransactionException.INSUFFICIENT_MAX_FEE_PER_GAS: (
220+
"transaction invalid gasPrice is less than the current BaseFee"
220221
),
221-
TransactionException.TYPE_3_TX_MAX_BLOB_GAS_ALLOWANCE_EXCEEDED: (
222-
"would exceed block maximum"
222+
TransactionException.PRIORITY_GREATER_THAN_MAX_FEE_PER_GAS: (
223+
"transaction invalid max priority fee per gas cannot be greater than max fee per gas"
223224
),
224-
TransactionException.INSUFFICIENT_MAX_FEE_PER_BLOB_GAS: (
225-
"max fee per blob gas less than block blob gas fee"
225+
TransactionException.TYPE_3_TX_INVALID_BLOB_VERSIONED_HASH: "Invalid versionedHash",
226+
TransactionException.TYPE_3_TX_CONTRACT_CREATION: (
227+
"transaction invalid transaction blob transactions must have a to address"
226228
),
227-
TransactionException.INSUFFICIENT_MAX_FEE_PER_GAS: (
228-
"gasPrice is less than the current BaseFee"
229+
TransactionException.TYPE_3_TX_WITH_FULL_BLOBS: (
230+
"Failed to decode transactions from block parameter"
229231
),
232+
TransactionException.TYPE_3_TX_ZERO_BLOBS: (
233+
"Failed to decode transactions from block parameter"
234+
),
235+
TransactionException.TYPE_3_TX_MAX_BLOB_GAS_ALLOWANCE_EXCEEDED: "Invalid Blob Count",
236+
TransactionException.TYPE_3_TX_BLOB_COUNT_EXCEEDED: "Invalid Blob Count",
230237
TransactionException.TYPE_3_TX_PRE_FORK: (
231-
"Transaction type BLOB is invalid, accepted transaction types are "
232-
"[EIP1559, ACCESS_LIST, FRONTIER]"
238+
"Transaction type BLOB is invalid, accepted transaction types are"
233239
),
234-
TransactionException.TYPE_3_TX_INVALID_BLOB_VERSIONED_HASH: (
235-
"Only supported hash version is 0x01, sha256 hash."
240+
TransactionException.TYPE_4_EMPTY_AUTHORIZATION_LIST: (
241+
"transaction invalid transaction code delegation transactions must have a "
242+
"non-empty code delegation list"
236243
),
237-
# This message is the same as TYPE_3_TX_MAX_BLOB_GAS_ALLOWANCE_EXCEEDED
238-
TransactionException.TYPE_3_TX_BLOB_COUNT_EXCEEDED: "exceed block maximum",
239-
TransactionException.TYPE_3_TX_ZERO_BLOBS: (
240-
"Blob transaction must have at least one versioned hash"
244+
TransactionException.TYPE_4_TX_CONTRACT_CREATION: (
245+
"transaction invalid transaction code delegation transactions must have a to address"
246+
),
247+
TransactionException.TYPE_4_TX_PRE_FORK: (
248+
"transaction invalid Transaction type DELEGATE_CODE is invalid"
249+
),
250+
TransactionException.INVALID_DEPOSIT_EVENT_LAYOUT: "Invalid deposit log",
251+
BlockException.RLP_STRUCTURES_ENCODING: (
252+
"Failed to decode transactions from block parameter"
253+
),
254+
BlockException.INCORRECT_EXCESS_BLOB_GAS: (
255+
"Payload excessBlobGas does not match calculated excessBlobGas"
256+
),
257+
BlockException.BLOB_GAS_USED_ABOVE_LIMIT: (
258+
"Payload BlobGasUsed does not match calculated BlobGasUsed"
259+
),
260+
BlockException.INCORRECT_BLOB_GAS_USED: (
261+
"Payload BlobGasUsed does not match calculated BlobGasUsed"
241262
),
242-
TransactionException.INTRINSIC_GAS_TOO_LOW: "intrinsic gas",
243-
TransactionException.INITCODE_SIZE_EXCEEDED: "exceeds maximum size",
244-
TransactionException.NONCE_MISMATCH_TOO_LOW: "below sender account nonce",
245263
# TODO EVMONE needs to differentiate when the section is missing in the header or body
246264
EOFException.MISSING_STOP_OPCODE: "err: no_terminating_instruction",
247265
EOFException.MISSING_CODE_HEADER: "err: code_section_missing",
@@ -283,4 +301,32 @@ class BesuExceptionMapper(ExceptionMapper):
283301
EOFException.TOO_MANY_CONTAINERS: "err: too_many_container_sections",
284302
EOFException.INVALID_CODE_SECTION_INDEX: "err: invalid_code_section_index",
285303
}
286-
mapping_regex: ClassVar[Dict[ExceptionBase, str]] = {}
304+
mapping_regex = {
305+
BlockException.INVALID_REQUESTS: (
306+
r"Invalid execution requests|Requests hash mismatch, calculated: 0x[0-9a-f]+ header: "
307+
r"0x[0-9a-f]+"
308+
),
309+
BlockException.INVALID_BLOCK_HASH: (
310+
r"Computed block hash 0x[0-9a-f]+ does not match block hash parameter 0x[0-9a-f]+"
311+
),
312+
BlockException.SYSTEM_CONTRACT_CALL_FAILED: (
313+
r"System call halted|System call did not execute to completion"
314+
),
315+
TransactionException.INITCODE_SIZE_EXCEEDED: (
316+
r"transaction invalid Initcode size of \d+ exceeds maximum size of \d+"
317+
),
318+
TransactionException.INSUFFICIENT_ACCOUNT_FUNDS: (
319+
r"transaction invalid transaction up-front cost 0x[0-9a-f]+ exceeds transaction "
320+
r"sender account balance 0x[0-9a-f]+"
321+
),
322+
TransactionException.INTRINSIC_GAS_TOO_LOW: (
323+
r"transaction invalid intrinsic gas cost \d+ exceeds gas limit \d+"
324+
),
325+
TransactionException.SENDER_NOT_EOA: (
326+
r"transaction invalid Sender 0x[0-9a-f]+ has deployed code and so is not authorized "
327+
r"to send transactions"
328+
),
329+
TransactionException.NONCE_MISMATCH_TOO_LOW: (
330+
r"transaction invalid transaction nonce \d+ below sender account nonce \d+"
331+
),
332+
}

src/ethereum_clis/clis/erigon.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
"""Erigon execution client transition tool."""
2+
3+
from ethereum_test_exceptions import BlockException, ExceptionMapper, TransactionException
4+
5+
6+
class ErigonExceptionMapper(ExceptionMapper):
7+
"""Erigon exception mapper."""
8+
9+
mapping_substring = {
10+
TransactionException.SENDER_NOT_EOA: "sender not an eoa",
11+
TransactionException.INITCODE_SIZE_EXCEEDED: "max initcode size exceeded",
12+
TransactionException.INSUFFICIENT_ACCOUNT_FUNDS: (
13+
"insufficient funds for gas * price + value"
14+
),
15+
TransactionException.INTRINSIC_GAS_TOO_LOW: "intrinsic gas too low",
16+
TransactionException.INSUFFICIENT_MAX_FEE_PER_GAS: "fee cap less than block base fee",
17+
TransactionException.PRIORITY_GREATER_THAN_MAX_FEE_PER_GAS: "tip higher than fee cap",
18+
TransactionException.INSUFFICIENT_MAX_FEE_PER_BLOB_GAS: "max fee per blob gas too low",
19+
TransactionException.NONCE_MISMATCH_TOO_LOW: "nonce too low",
20+
TransactionException.TYPE_3_TX_PRE_FORK: "blob txn is not supported by signer",
21+
TransactionException.TYPE_3_TX_INVALID_BLOB_VERSIONED_HASH: (
22+
"invalid blob versioned hash, must start with VERSIONED_HASH_VERSION_KZG"
23+
),
24+
TransactionException.TYPE_3_TX_ZERO_BLOBS: "a blob stx must contain at least one blob",
25+
TransactionException.TYPE_3_TX_WITH_FULL_BLOBS: "rlp: expected String or Byte",
26+
TransactionException.TYPE_3_TX_CONTRACT_CREATION: "wrong size for To: 0",
27+
TransactionException.TYPE_3_TX_MAX_BLOB_GAS_ALLOWANCE_EXCEEDED: (
28+
"blobs/blobgas exceeds max"
29+
),
30+
TransactionException.TYPE_4_EMPTY_AUTHORIZATION_LIST: (
31+
"SetCodeTransaction without authorizations is invalid"
32+
),
33+
TransactionException.TYPE_4_TX_CONTRACT_CREATION: "wrong size for To: 0",
34+
TransactionException.TYPE_4_TX_PRE_FORK: "setCode tx is not supported by signer",
35+
TransactionException.INVALID_DEPOSIT_EVENT_LAYOUT: "could not parse requests logs",
36+
BlockException.INVALID_REQUESTS: "invalid requests root hash in header",
37+
BlockException.INVALID_BLOCK_HASH: "invalid block hash",
38+
}
39+
mapping_regex = {
40+
BlockException.INCORRECT_BLOB_GAS_USED: r"blobGasUsed by execution: \d+, in header: \d+",
41+
BlockException.INCORRECT_EXCESS_BLOB_GAS: r"invalid excessBlobGas: have \d+, want \d+",
42+
}

src/ethereum_clis/clis/ethereumjs.py

Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from typing import ClassVar, Dict, Optional
66

77
from ethereum_test_exceptions import (
8+
BlockException,
89
EOFException,
910
ExceptionBase,
1011
ExceptionMapper,
@@ -48,30 +49,45 @@ class EthereumJSExceptionMapper(ExceptionMapper):
4849
"""Translate between EEST exceptions and error strings returned by EthereumJS."""
4950

5051
mapping_substring: ClassVar[Dict[ExceptionBase, str]] = {
51-
TransactionException.TYPE_4_TX_CONTRACT_CREATION: (
52-
"set code transaction must not be a create transaction"
53-
),
54-
TransactionException.INSUFFICIENT_ACCOUNT_FUNDS: (
55-
"insufficient funds for gas * price + value"
56-
),
5752
TransactionException.TYPE_3_TX_MAX_BLOB_GAS_ALLOWANCE_EXCEEDED: (
5853
"would exceed maximum allowance"
5954
),
6055
TransactionException.INSUFFICIENT_MAX_FEE_PER_BLOB_GAS: (
61-
"max fee per blob gas less than block blob gas fee"
56+
"Invalid 4844 transactions: undefined"
6257
),
6358
TransactionException.INSUFFICIENT_MAX_FEE_PER_GAS: (
64-
"max fee per gas less than block base fee"
59+
"tx unable to pay base fee (EIP-1559 tx)"
6560
),
66-
TransactionException.TYPE_3_TX_PRE_FORK: (
67-
"blob tx used but field env.ExcessBlobGas missing"
61+
TransactionException.PRIORITY_GREATER_THAN_MAX_FEE_PER_GAS: (
62+
"maxFeePerGas cannot be less than maxPriorityFeePerGas"
63+
),
64+
TransactionException.TYPE_3_TX_INVALID_BLOB_VERSIONED_HASH: (
65+
"versioned hash does not start with KZG commitment version"
6866
),
69-
TransactionException.TYPE_3_TX_INVALID_BLOB_VERSIONED_HASH: "has invalid hash version",
7067
# This message is the same as TYPE_3_TX_MAX_BLOB_GAS_ALLOWANCE_EXCEEDED
7168
TransactionException.TYPE_3_TX_BLOB_COUNT_EXCEEDED: "exceed maximum allowance",
72-
TransactionException.TYPE_3_TX_ZERO_BLOBS: "blob transaction missing blob hashes",
69+
TransactionException.TYPE_3_TX_ZERO_BLOBS: "tx should contain at least one blob",
70+
TransactionException.TYPE_3_TX_WITH_FULL_BLOBS: "Invalid EIP-4844 transaction",
71+
TransactionException.TYPE_3_TX_CONTRACT_CREATION: (
72+
'tx should have a "to" field and cannot be used to create contracts'
73+
),
74+
TransactionException.TYPE_4_EMPTY_AUTHORIZATION_LIST: (
75+
"Invalid EIP-7702 transaction: authorization list is empty"
76+
),
7377
TransactionException.INTRINSIC_GAS_TOO_LOW: "is lower than the minimum gas limit of",
74-
TransactionException.INITCODE_SIZE_EXCEEDED: "max initcode size exceeded",
78+
TransactionException.INITCODE_SIZE_EXCEEDED: (
79+
"the initcode size of this transaction is too large"
80+
),
81+
TransactionException.TYPE_4_TX_CONTRACT_CREATION: (
82+
'tx should have a "to" field and cannot be used to create contracts'
83+
),
84+
TransactionException.INSUFFICIENT_ACCOUNT_FUNDS: (
85+
"sender doesn't have enough funds to send tx"
86+
),
87+
TransactionException.NONCE_MISMATCH_TOO_LOW: "the tx doesn't have the correct nonce",
88+
TransactionException.INVALID_DEPOSIT_EVENT_LAYOUT: "Error verifying block while running",
89+
BlockException.INCORRECT_EXCESS_BLOB_GAS: "Invalid 4844 transactions",
90+
BlockException.INVALID_RECEIPTS_ROOT: "invalid receipttrie",
7591
# TODO EVMONE needs to differentiate when the section is missing in the header or body
7692
EOFException.MISSING_STOP_OPCODE: "err: no_terminating_instruction",
7793
EOFException.MISSING_CODE_HEADER: "err: code_section_missing",
@@ -113,4 +129,22 @@ class EthereumJSExceptionMapper(ExceptionMapper):
113129
EOFException.TOO_MANY_CONTAINERS: "err: too_many_container_sections",
114130
EOFException.INVALID_CODE_SECTION_INDEX: "err: invalid_code_section_index",
115131
}
116-
mapping_regex: ClassVar[Dict[ExceptionBase, str]] = {}
132+
mapping_regex: ClassVar[Dict[ExceptionBase, str]] = {
133+
TransactionException.TYPE_3_TX_MAX_BLOB_GAS_ALLOWANCE_EXCEEDED: (
134+
r"tx causes total blob gas of \d+ to exceed maximum blob gas per block of \d+|"
135+
r"tx can contain at most \d+ blobs"
136+
),
137+
TransactionException.TYPE_3_TX_BLOB_COUNT_EXCEEDED: (
138+
r"tx causes total blob gas of \d+ to exceed maximum blob gas per block of \d+|"
139+
r"tx can contain at most \d+ blobs"
140+
),
141+
TransactionException.TYPE_3_TX_PRE_FORK: (
142+
r"blob tx used but field env.ExcessBlobGas missing|EIP-4844 not enabled on Common"
143+
),
144+
BlockException.BLOB_GAS_USED_ABOVE_LIMIT: r"invalid blobGasUsed expected=\d+ actual=\d+",
145+
BlockException.INCORRECT_BLOB_GAS_USED: r"invalid blobGasUsed expected=\d+ actual=\d+",
146+
BlockException.INVALID_BLOCK_HASH: (
147+
r"Invalid blockHash, expected: 0x[0-9a-f]+, received: 0x[0-9a-f]+"
148+
),
149+
BlockException.INVALID_REQUESTS: r"Unknown request identifier|invalid requestshash",
150+
}

0 commit comments

Comments
 (0)