Skip to content

Commit 59379a8

Browse files
new(tests): EIP-7702: Updates for Devnet-3 (#733)
* feat(base_types): Add `keccak256` to `Bytes` * fix(fw): EIP-7702 types update * fix(types): nonce list logic removal * feat(types): Calculate signer if v,r,s parameters are in the Auth Tuple * feat(types/filler): Allow delegation on `pre.fund_eoa` * feat(types): Add `Literal["Self"]` as option to delegation in `pre.fund_eoa` * fix(plugins/filler): fix delegation check * fix(plugins/filler): delegation designation in case of `None` * feat(evm_transition_tool): `SetCodeDelegation` to transaction receipt * new(tests): EIP-7702 spec update * new(tests): EIP-7702 add all invalid auth tuples test * new(tests): EIP-7702 add multiple valid, self-sponsored test * fix(tests): EIP-7702 enable skipped tests * refactor(tests): EIP-7702 rename folder and files * new(tests): EIP-7702, some failing tests * fix(tests): EIP-7702 gas test * fix(tests): EIP-7702 move gas tests * new(tests): EIP-7702 intrinsic gas tests * fix(fixtures): tests * fix(tests): import * simplify parametrization * refactor(tests): EIP-7702 gas tests * new(tests): EIP-7702 more gas tests * new(tests): EIP-7702 parametrize and add new tests * fix(tests): EIP-7702 add check * feat(exceptions): Add two type-4 tx exceptions * new(tests): EIP-7702 tests * fix(tests): Update tests according to spec changes ethereum/EIPs#8795 * fix(tests): EIP-7702, use `named_parametrize` * fix(tests): EIP-7702 test not following spec * fix(tests): EIP-7702 test authorization list nonce/gas * fix(tests): EIP-7702 fix test_ext_code_on_chain_delegating_set_code * fix(tests): EIP-7702 fix test_set_code_all_invalid_authorization_tuples * fix(tests): EIP-7702 fix test_set_code_invalid_authorization_tuple * fix(tests): EIP-7702 system-contract tests * fix(tests): EIP-7702 tox * refactor(tests): EIP-7702 `parametrize_with_defaults` rename * fix(tests): EIP-7702 test_ext_code_on_set_code * fix(tests): EIP-7702 test_ext_code_on_set_code * fix(tests): EIP-7702 test_set_code_to_sstore * fix(tests): EIP-7702, add delegation designation to all expected outputs * fix(tests): EIP-7702, add delegation designation * new(tests): EIP-7702, add eoa tx after set code tests * refactor(tests): EIP-7702 update for parametrize_with_defaults -> extend_with_defaults (#758) * fix(tests): Marker * fix(tests): EIP-7702: pre-existing delegation gas tests * fix(tests): EIP-7702: fix warm costs expectations * fix(tests): EIP-7702 re-authorization tests * fix(tests): EIP-7702 warm account logic revamp * fix(tests): EIP-7702 test fixes * feat(tests): EIP-7702 add self-delegation warm cost test * fix(test): EIP-7702, test_call_into_self_delegating_set_code * fix(tests): EIP-7702 use kwargs on `with_all` markers * docs: Changelog * fix(tests): EIP-7702 return code expectations * fix(tests): EIP-7702 invalid tx on invalid signatures * Apply suggestions from code review Co-authored-by: danceratopz <[email protected]> --------- Co-authored-by: danceratopz <[email protected]>
1 parent db13a63 commit 59379a8

File tree

15 files changed

+3816
-965
lines changed

15 files changed

+3816
-965
lines changed

docs/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Test fixtures for use by clients are available for each release on the [Github r
1111
- ✨ EIP-4844 test `tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py` includes an EOF test case ([#610](https://github.com/ethereum/execution-spec-tests/pull/610)).
1212
- ✨ Example test `tests/frontier/opcodes/test_dup.py` now includes EOF parametrization ([#610](https://github.com/ethereum/execution-spec-tests/pull/610)).
1313
- ✨ Convert all opcodes validation test `tests/frontier/opcodes/test_all_opcodes.py` ([#748](https://github.com/ethereum/execution-spec-tests/pull/748)).
14+
- ✨ Update [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) tests for Devnet-3 ([#733](https://github.com/ethereum/execution-spec-tests/pull/733))
1415

1516
### 🛠️ Framework
1617

src/ethereum_test_base_types/base_types.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
from typing import Any, ClassVar, SupportsBytes, Type, TypeVar
66

7+
from Crypto.Hash import keccak
78
from pydantic import GetCoreSchemaHandler
89
from pydantic_core.core_schema import (
910
PlainValidatorFunctionSchema,
@@ -146,6 +147,13 @@ def or_none(cls, input: "Bytes | BytesConvertible | None") -> "Bytes | None":
146147
return input
147148
return cls(input)
148149

150+
def keccak256(self) -> "Bytes":
151+
"""
152+
Return the keccak256 hash of the opcode byte representation.
153+
"""
154+
k = keccak.new(digest_bits=256)
155+
return Bytes(k.update(bytes(self)).digest())
156+
149157

150158
S = TypeVar("S", bound="FixedSizeHexNumber")
151159

src/ethereum_test_exceptions/exceptions.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,14 @@ class TransactionException(ExceptionBase):
354354
"""
355355
Transaction is type 3, but has no blobs.
356356
"""
357+
TYPE_4_EMPTY_AUTHORIZATION_LIST = auto()
358+
"""
359+
Transaction is type 4, but has an empty authorization list.
360+
"""
361+
TYPE_4_INVALID_AUTHORITY_SIGNATURE = auto()
362+
"""
363+
Transaction is type 4, but has an empty authorization list.
364+
"""
357365

358366

359367
@unique

src/ethereum_test_fixtures/tests/test_blockchain.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@
191191
AuthorizationTuple(
192192
chain_id=1,
193193
address=2,
194-
nonce=[3],
194+
nonce=3,
195195
signer=EOA(key=TestPrivateKey),
196196
)
197197
],
@@ -212,16 +212,16 @@
212212
{
213213
"chainId": "0x01",
214214
"address": Address(2).hex(),
215-
"nonce": ["0x03"],
215+
"nonce": "0x03",
216216
"v": "0x00",
217-
"r": "0x796b0a59fe796b5aab79259988f4b18bb7966dc9aa0a01d226859057f539d8f6",
218-
"s": "0x7456ad9b8b4e157d8a150ae7d568bb93e668bf1d5970756f7fe7b7f2472235fe",
217+
"r": "0xda29c3bd0304ae475b06d1a11344e0b6d75590f2c23138c9507f4b5bedde3c79",
218+
"s": "0x3e1fb143ae0460373d567cf901645757b321e42c423a53b2d46ed13c9ef0a9ab",
219219
"signer": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
220220
}
221221
],
222222
"v": "0x01",
223-
"r": "0xb9f3ad929ffdb846cbe357fa25e6ab93cc6e10e76da170a12baf03f8a34ba141",
224-
"s": "0x04992060cfa252f5ac18ac1ccb340a821497d50812a225646094d2ad08b8eeaa",
223+
"r": "0xe7da7f244c95cea73ac6316971139ac0eb8fad455d9a25e1c134d7a157c38ff9",
224+
"s": "0x1939185d2e2a2b3375183e42b5755d695efbd72e186cf9a3e6958a3fb84cc709",
225225
"sender": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
226226
},
227227
id="fixture_transaction_type_4",

src/ethereum_test_types/types.py

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
from dataclasses import dataclass
66
from functools import cached_property
7-
from typing import Any, ClassVar, Dict, Generic, List, Sequence, Tuple
7+
from typing import Any, ClassVar, Dict, Generic, List, Literal, Sequence, Tuple
88

99
from coincurve.keys import PrivateKey, PublicKey
1010
from ethereum import rlp as eth_rlp
@@ -283,6 +283,7 @@ def fund_eoa(
283283
amount: NumberConvertible = 10**21,
284284
label: str | None = None,
285285
storage: Storage | None = None,
286+
delegation: Address | Literal["Self"] | None = None,
286287
) -> EOA:
287288
"""
288289
Add a previously unused EOA to the pre-alloc with the balance specified by `amount`.
@@ -469,34 +470,24 @@ class AuthorizationTupleGeneric(CamelModel, Generic[NumberBoundTypeVar]):
469470
Authorization tuple for transactions.
470471
"""
471472

472-
chain_id: NumberBoundTypeVar = Field(1) # type: ignore
473+
chain_id: NumberBoundTypeVar = Field(0) # type: ignore
473474
address: Address
474-
nonce: List[NumberBoundTypeVar] = Field(default_factory=list)
475+
nonce: NumberBoundTypeVar = Field(0) # type: ignore
475476

476477
v: NumberBoundTypeVar = Field(0) # type: ignore
477478
r: NumberBoundTypeVar = Field(0) # type: ignore
478479
s: NumberBoundTypeVar = Field(0) # type: ignore
479480

480481
magic: ClassVar[int] = 0x05
481482

482-
@model_validator(mode="before")
483-
@classmethod
484-
def convert_nonce_information(cls, data: Any) -> Any:
485-
"""
486-
Automatically converts the nonce to a list if it is not already.
487-
"""
488-
if "nonce" in data and not isinstance(data["nonce"], list):
489-
data["nonce"] = [data["nonce"]]
490-
return data
491-
492483
def to_list(self) -> List[Any]:
493484
"""
494485
Returns the authorization tuple as a list of serializable elements.
495486
"""
496487
return [
497488
Uint(self.chain_id),
498489
self.address,
499-
[Uint(n) for n in self.nonce],
490+
Uint(self.nonce),
500491
Uint(self.v),
501492
Uint(self.r),
502493
Uint(self.s),
@@ -511,7 +502,7 @@ def signing_bytes(self) -> bytes:
511502
[
512503
Uint(self.chain_id),
513504
self.address,
514-
[Uint(n) for n in self.nonce],
505+
Uint(self.nonce),
515506
]
516507
)
517508

@@ -548,6 +539,27 @@ def model_post_init(self, __context: Any) -> None:
548539
elif self.signer is not None:
549540
assert self.signer.key is not None, "signer must have a key"
550541
self.sign(self.signer.key)
542+
else:
543+
assert self.v is not None, "v must be set"
544+
assert self.r is not None, "r must be set"
545+
assert self.s is not None, "s must be set"
546+
547+
# Calculate the address from the signature
548+
try:
549+
signature_bytes = (
550+
int(self.r).to_bytes(32, byteorder="big")
551+
+ int(self.s).to_bytes(32, byteorder="big")
552+
+ bytes([self.v])
553+
)
554+
public_key = PublicKey.from_signature_and_message(
555+
signature_bytes, keccak256(self.signing_bytes), hasher=None
556+
)
557+
self.signer = EOA(
558+
address=Address(keccak256(public_key.format(compressed=False)[1:])[32 - 20 :])
559+
)
560+
except Exception:
561+
# Signer remains `None` in this case
562+
pass
551563

552564
def sign(self, private_key: Hash) -> None:
553565
"""

src/evm_transition_tool/types.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,16 @@ class TransactionLog(CamelModel):
3333
removed: bool
3434

3535

36+
class SetCodeDelegation(CamelModel):
37+
"""
38+
Set code delegation
39+
"""
40+
41+
from_address: Address = Field(..., alias="from")
42+
nonce: HexNumber
43+
target: Address
44+
45+
3646
class TransactionReceipt(CamelModel):
3747
"""
3848
Transaction receipt
@@ -51,6 +61,7 @@ class TransactionReceipt(CamelModel):
5161
transaction_index: HexNumber | None = None
5262
blob_gas_used: HexNumber | None = None
5363
blob_gas_price: HexNumber | None = None
64+
delegations: List[SetCodeDelegation] | None = None
5465

5566

5667
class RejectedTransaction(CamelModel):

src/pytest_plugins/filler/pre_alloc.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from enum import IntEnum
77
from functools import cache
88
from itertools import count
9-
from typing import Iterator
9+
from typing import Iterator, Literal
1010

1111
import pytest
1212
from pydantic import PrivateAttr
@@ -86,6 +86,9 @@ class AllocMode(IntEnum):
8686
STRICT = 1
8787

8888

89+
DELEGATION_DESIGNATION = b"\xef\x01\x00"
90+
91+
8992
class Alloc(BaseAlloc):
9093
"""
9194
Allocation of accounts in the state, pre and post test execution.
@@ -193,6 +196,7 @@ def fund_eoa(
193196
amount: NumberConvertible = 10**21,
194197
label: str | None = None,
195198
storage: Storage | None = None,
199+
delegation: Address | Literal["Self"] | None = None,
196200
) -> EOA:
197201
"""
198202
Add a previously unused EOA to the pre-alloc with the balance specified by `amount`.
@@ -201,18 +205,23 @@ def fund_eoa(
201205
returned.
202206
"""
203207
eoa = next(self._eoa_iterator)
204-
if Number(amount) > 0 or storage is not None:
205-
if storage is None:
208+
if Number(amount) > 0 or storage is not None or delegation is not None:
209+
if storage is None and delegation is None:
206210
account = Account(
207211
nonce=0,
208212
balance=amount,
209213
)
210214
else:
211215
# Type-4 transaction is sent to the EOA to set the storage, so the nonce must be 1
216+
if not isinstance(delegation, Address) and delegation == "Self":
217+
delegation = eoa
212218
account = Account(
213219
nonce=1,
214220
balance=amount,
215-
storage=storage,
221+
storage=storage if storage is not None else {},
222+
code=DELEGATION_DESIGNATION + bytes(delegation) # type: ignore
223+
if delegation is not None
224+
else b"",
216225
)
217226
eoa.nonce = Number(1)
218227

tests/prague/eip7702_eoa_code_tx/spec.py

Lines changed: 0 additions & 29 deletions
This file was deleted.

0 commit comments

Comments
 (0)