11"""Helper functions."""
22
33from dataclasses import dataclass
4- from typing import Dict , List
4+ from typing import Any , Dict , List
55
66import pytest
77
88from ethereum_clis import Result
99from ethereum_test_exceptions import ExceptionBase , ExceptionMapper , UndefinedException
10- from ethereum_test_types import Transaction
10+ from ethereum_test_types import Transaction , TransactionReceipt
1111
1212
13- class TransactionExpectedToFailSucceedError (Exception ):
14- """Exception used when the transaction expected to return an error, did succeed ."""
13+ class TransactionUnexpectedSuccessError (Exception ):
14+ """Exception used when the transaction expected to fail succeeded instead ."""
1515
1616 def __init__ (self , index : int , nonce : int ):
1717 """Initialize the exception with the transaction index and nonce."""
@@ -23,7 +23,7 @@ def __init__(self, index: int, nonce: int):
2323
2424
2525class TransactionUnexpectedFailError (Exception ):
26- """Exception used when the transaction expected to succeed, did fail ."""
26+ """Exception used when the transaction expected to succeed failed instead ."""
2727
2828 def __init__ (self , index : int , nonce : int , message : str , exception : ExceptionBase ):
2929 """Initialize the exception."""
@@ -70,12 +70,32 @@ def __init__(
7070 super ().__init__ (message )
7171
7272
73+ class TransactionReceiptMismatchError (Exception ):
74+ """Exception used when the actual transaction receipt differs from the expected one."""
75+
76+ def __init__ (
77+ self ,
78+ index : int ,
79+ field_name : str ,
80+ expected_value : Any ,
81+ actual_value : Any ,
82+ ):
83+ """Initialize the exception."""
84+ message = (
85+ f"\n TransactionReceiptMismatch (pos={ index } ):"
86+ f"\n What: { field_name } mismatch!"
87+ f"\n Want: { expected_value } "
88+ f"\n Got: { actual_value } "
89+ )
90+ super ().__init__ (message )
91+
92+
7393@dataclass
7494class TransactionExceptionInfo :
7595 """Info to print transaction exception error messages."""
7696
7797 t8n_error_message : str | None
78- transaction_ind : int
98+ transaction_index : int
7999 tx : Transaction
80100
81101
@@ -89,12 +109,10 @@ def verify_transaction_exception(
89109
90110 # info.tx.error is expected error code defined in .py test
91111 if expected_error and not info .t8n_error_message :
92- raise TransactionExpectedToFailSucceedError (
93- index = info .transaction_ind , nonce = info .tx .nonce
94- )
112+ raise TransactionUnexpectedSuccessError (index = info .transaction_index , nonce = info .tx .nonce )
95113 elif not expected_error and info .t8n_error_message :
96114 raise TransactionUnexpectedFailError (
97- index = info .transaction_ind ,
115+ index = info .transaction_index ,
98116 nonce = info .tx .nonce ,
99117 message = info .t8n_error_message ,
100118 exception = exception_mapper .message_to_exception (info .t8n_error_message ),
@@ -122,7 +140,7 @@ def verify_transaction_exception(
122140
123141 if expected_error_msg is None or expected_error_msg not in info .t8n_error_message :
124142 raise TransactionExceptionMismatchError (
125- index = info .transaction_ind ,
143+ index = info .transaction_index ,
126144 nonce = info .tx .nonce ,
127145 expected_exception = expected_exception ,
128146 expected_message = expected_error_msg ,
@@ -132,21 +150,59 @@ def verify_transaction_exception(
132150 )
133151
134152
153+ def verify_transaction_receipt (
154+ transaction_index : int ,
155+ expected_receipt : TransactionReceipt | None ,
156+ actual_receipt : TransactionReceipt | None ,
157+ ):
158+ """
159+ Verify the actual receipt against the expected one.
160+
161+ If the expected receipt is None, validation is skipped.
162+
163+ Only verifies non-None values in the expected receipt if any.
164+ """
165+ if expected_receipt is None :
166+ return
167+ assert actual_receipt is not None
168+ if (
169+ expected_receipt .gas_used is not None
170+ and actual_receipt .gas_used != expected_receipt .gas_used
171+ ):
172+ raise TransactionReceiptMismatchError (
173+ index = transaction_index ,
174+ field_name = "gas_used" ,
175+ expected_value = expected_receipt .gas_used ,
176+ actual_value = actual_receipt .gas_used ,
177+ )
178+ # TODO: Add more fields as needed
179+
180+
135181def verify_transactions (
136- exception_mapper : ExceptionMapper , txs : List [Transaction ], result : Result
182+ * ,
183+ txs : List [Transaction ],
184+ exception_mapper : ExceptionMapper ,
185+ result : Result ,
137186) -> List [int ]:
138187 """
139- Verify rejected transactions (if any) against the expected outcome.
140- Raises exception on unexpected rejections or unexpected successful txs.
188+ Verify accepted and rejected (if any) transactions against the expected outcome.
189+ Raises exception on unexpected rejections, unexpected successful txs, or successful txs with
190+ unexpected receipt values.
141191 """
142192 rejected_txs : Dict [int , str ] = {
143193 rejected_tx .index : rejected_tx .error for rejected_tx in result .rejected_transactions
144194 }
145195
196+ receipt_index = 0
146197 for i , tx in enumerate (txs ):
147198 error_message = rejected_txs [i ] if i in rejected_txs else None
148- info = TransactionExceptionInfo (t8n_error_message = error_message , transaction_ind = i , tx = tx )
199+ info = TransactionExceptionInfo (
200+ t8n_error_message = error_message , transaction_index = i , tx = tx
201+ )
149202 verify_transaction_exception (exception_mapper = exception_mapper , info = info )
203+ if error_message is None :
204+ verify_transaction_receipt (i , tx .expected_receipt , result .receipts [receipt_index ])
205+ receipt_index += 1
150206
151207 return list (rejected_txs .keys ())
152208
0 commit comments