Skip to content

Commit e91a712

Browse files
authored
Merge pull request #888 from ethereum/pre-reqs-for-devnet-4-updates
feat(fw): Changes required for Devnet-4 Tests
2 parents 0900aa8 + 818c87f commit e91a712

File tree

9 files changed

+80
-10
lines changed

9 files changed

+80
-10
lines changed

docs/CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,9 @@ Test fixtures for use by clients are available for each release on the [Github r
4646
- ✨ Add `Wei` type to `ethereum_test_base_types` which allows parsing wei amounts from strings like "1 ether", "1000 wei", "10**2 gwei", etc ([#825](https://github.com/ethereum/execution-spec-tests/pull/825)).
4747
- ✨ Pin EELS versions in `eels_resolutions.json` and include this file in fixture releases ([#872](https://github.com/ethereum/execution-spec-tests/pull/872)).
4848
- 🔀 Replace `ethereum.base_types` with `ethereum-types` ([#850](https://github.com/ethereum/execution-spec-tests/pull/850)).
49-
- 💥 `PragueEIP7692` fork has been renamed to `Osaka` ([#869](https://github.com/ethereum/execution-spec-tests/pull/869))
49+
- 💥 Rename the `PragueEIP7692` fork to `Osaka` ([#869](https://github.com/ethereum/execution-spec-tests/pull/869)).
5050
- ✨ Improve `fill` terminal output to emphasize that filling tests is not actually testing a client ([#807](https://github.com/ethereum/execution-spec-tests/pull/887)).
51+
- ✨ Add the `BlockchainTestEngine` test spec type that only generates a fixture in the `EngineFixture` (`blockchain_test_engine`) format ([#888](https://github.com/ethereum/execution-spec-tests/pull/888)).
5152

5253
### 🔧 EVM Tools
5354

docs/writing_tests/writing_a_new_test.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ def test_contract_creating_tx(
7676

7777
The `state_test` and `blockchain_test` objects are actually wrapper classes to the `StateTest`, respectively `BlockchainTest` objects, that once called actually instantiate a new instance of these objects and fill the test case using the `evm` tool according to the pre and post states and the transactions defined within the test.
7878

79+
If a blockchain-type test should only generate a test fixture in the Engine format (`EngineFixture`), the `blockchain_test_engine` object can be specified. This object is a wrapper for the `BlockchainTestEngine` class.
80+
7981
## `StateTest` Object
8082

8183
The `StateTest` object represents a single test vector, and contains the
@@ -100,6 +102,10 @@ Ethereum VM by attempting to append multiple blocks to the chain:
100102
created or modified after all blocks are executed.
101103
- `blocks`: All blocks to be appended to the blockchain during the test.
102104

105+
## `BlockchainTestEngine` Object
106+
107+
The `BlockchainTestEngine` object has the same properties as the `BlockchainTest` but it's used to only generate a blockchain test in the Engine format.
108+
103109
## Pre/Post State of the Test
104110

105111
The `pre` and `post` states are elemental to setup and then verify the outcome

src/ethereum_test_base_types/base_types.py

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
Basic type primitives used to define other types.
33
"""
44

5+
from hashlib import sha256
56
from typing import Any, ClassVar, SupportsBytes, Type, TypeVar
67

78
from Crypto.Hash import keccak
@@ -162,7 +163,7 @@ class Bytes(bytes, ToStringSchema):
162163
Class that helps represent bytes of variable length in tests.
163164
"""
164165

165-
def __new__(cls, input: BytesConvertible):
166+
def __new__(cls, input: BytesConvertible = b""):
166167
"""
167168
Creates a new Bytes object.
168169
"""
@@ -204,6 +205,12 @@ def keccak256(self) -> "Hash":
204205
k = keccak.new(digest_bits=256)
205206
return Hash(k.update(bytes(self)).digest())
206207

208+
def sha256(self) -> "Hash":
209+
"""
210+
Return the sha256 hash of the opcode byte representation.
211+
"""
212+
return Hash(sha256(self).digest())
213+
207214

208215
S = TypeVar("S", bound="FixedSizeHexNumber")
209216

@@ -279,6 +286,7 @@ class FixedSizeBytes(Bytes):
279286
"""
280287

281288
byte_length: ClassVar[int]
289+
_sized_: ClassVar[Type["FixedSizeBytes"]]
282290

283291
def __class_getitem__(cls, length: int) -> Type["FixedSizeBytes"]:
284292
"""
@@ -288,6 +296,7 @@ def __class_getitem__(cls, length: int) -> Type["FixedSizeBytes"]:
288296
class Sized(cls): # type: ignore
289297
byte_length = length
290298

299+
Sized._sized_ = Sized
291300
return Sized
292301

293302
def __new__(cls, input: FixedSizeBytesConvertible | T):
@@ -317,14 +326,16 @@ def __eq__(self, other: object) -> bool:
317326
"""
318327
Compares two FixedSizeBytes objects to be equal.
319328
"""
329+
if other is None:
330+
return False
320331
if not isinstance(other, FixedSizeBytes):
321332
assert (
322333
isinstance(other, str)
323334
or isinstance(other, int)
324335
or isinstance(other, bytes)
325336
or isinstance(other, SupportsBytes)
326337
)
327-
other = self.__class__(other)
338+
other = self._sized_(other)
328339
return super().__eq__(other)
329340

330341
def __ne__(self, other: object) -> bool:
@@ -341,6 +352,17 @@ class Address(FixedSizeBytes[20]): # type: ignore
341352

342353
label: str | None = None
343354

355+
def __new__(cls, input: "FixedSizeBytesConvertible | Address", *, label: str | None = None):
356+
"""
357+
Creates a new Address object with an optional label.
358+
"""
359+
instance = super(Address, cls).__new__(cls, input)
360+
if isinstance(input, Address) and label is None:
361+
instance.label = input.label
362+
else:
363+
instance.label = label
364+
return instance
365+
344366

345367
class Hash(FixedSizeBytes[32]): # type: ignore
346368
"""

src/ethereum_test_specs/__init__.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,14 @@
55
from typing import List, Type
66

77
from .base import BaseTest, TestSpec
8-
from .blockchain import BlockchainTest, BlockchainTestFiller, BlockchainTestSpec
8+
from .blockchain import (
9+
BlockchainTest,
10+
BlockchainTestEngine,
11+
BlockchainTestEngineFiller,
12+
BlockchainTestEngineSpec,
13+
BlockchainTestFiller,
14+
BlockchainTestSpec,
15+
)
916
from .eof import (
1017
EOFStateTest,
1118
EOFStateTestFiller,
@@ -18,6 +25,7 @@
1825

1926
SPEC_TYPES: List[Type[BaseTest]] = [
2027
BlockchainTest,
28+
BlockchainTestEngine,
2129
StateTest,
2230
StateTestOnly,
2331
EOFTest,
@@ -29,6 +37,9 @@
2937
"SPEC_TYPES",
3038
"BaseTest",
3139
"BlockchainTest",
40+
"BlockchainTestEngine",
41+
"BlockchainTestEngineFiller",
42+
"BlockchainTestEngineSpec",
3243
"BlockchainTestFiller",
3344
"BlockchainTestSpec",
3445
"EOFStateTest",

src/ethereum_test_specs/blockchain.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -751,3 +751,17 @@ def generate(
751751

752752
BlockchainTestSpec = Callable[[str], Generator[BlockchainTest, None, None]]
753753
BlockchainTestFiller = Type[BlockchainTest]
754+
755+
756+
class BlockchainTestEngine(BlockchainTest):
757+
"""
758+
Filler type that tests multiple blocks (valid or invalid) in a chain, only for the Engine API.
759+
"""
760+
761+
supported_fixture_formats: ClassVar[List[FixtureFormat]] = [
762+
BlockchainEngineFixture,
763+
]
764+
765+
766+
BlockchainTestEngineSpec = Callable[[str], Generator[BlockchainTestEngine, None, None]]
767+
BlockchainTestEngineFiller = Type[BlockchainTestEngine]

src/ethereum_test_tools/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
SPEC_TYPES,
2626
BaseTest,
2727
BlockchainTest,
28+
BlockchainTestEngine,
29+
BlockchainTestEngineFiller,
2830
BlockchainTestFiller,
2931
EOFStateTest,
3032
EOFStateTestFiller,
@@ -93,6 +95,8 @@
9395
"BaseTest",
9496
"Block",
9597
"BlockchainTest",
98+
"BlockchainTestEngine",
99+
"BlockchainTestEngineFiller",
96100
"BlockchainTestFiller",
97101
"BlockException",
98102
"Bytecode",

src/ethereum_test_tools/code/generators.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from dataclasses import dataclass
66
from typing import List, SupportsBytes
77

8+
from ethereum_test_base_types import Bytes
89
from ethereum_test_types import ceiling_division
910
from ethereum_test_vm import Bytecode, EVMCodeType
1011
from ethereum_test_vm import Opcodes as Op
@@ -27,7 +28,7 @@ class Initcode(Bytecode):
2728
costs.
2829
"""
2930

30-
deploy_code: SupportsBytes
31+
deploy_code: SupportsBytes | Bytes
3132
"""
3233
Bytecode to be deployed by the initcode.
3334
"""
@@ -44,7 +45,7 @@ class Initcode(Bytecode):
4445
def __new__(
4546
cls,
4647
*,
47-
deploy_code: SupportsBytes = Bytecode(),
48+
deploy_code: SupportsBytes | Bytes = Bytecode(),
4849
initcode_length: int | None = None,
4950
initcode_prefix: Bytecode = Bytecode(),
5051
initcode_prefix_execution_gas: int = 0,

src/ethereum_test_types/types.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,7 @@ def fund_eoa(
310310
label: str | None = None,
311311
storage: Storage | None = None,
312312
delegation: Address | Literal["Self"] | None = None,
313+
nonce: NumberConvertible | None = None,
313314
) -> EOA:
314315
"""
315316
Add a previously unused EOA to the pre-alloc with the balance specified by `amount`.

src/pytest_plugins/filler/pre_alloc.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ def fund_eoa(
199199
label: str | None = None,
200200
storage: Storage | None = None,
201201
delegation: Address | Literal["Self"] | None = None,
202+
nonce: NumberConvertible | None = None,
202203
) -> EOA:
203204
"""
204205
Add a previously unused EOA to the pre-alloc with the balance specified by `amount`.
@@ -209,25 +210,34 @@ def fund_eoa(
209210
eoa = next(self._eoa_iterator)
210211
if amount is None:
211212
amount = self._eoa_fund_amount_default
212-
if Number(amount) > 0 or storage is not None or delegation is not None:
213+
if (
214+
Number(amount) > 0
215+
or storage is not None
216+
or delegation is not None
217+
or (nonce is not None and Number(nonce) > 0)
218+
):
213219
if storage is None and delegation is None:
220+
nonce = Number(0 if nonce is None else nonce)
214221
account = Account(
215-
nonce=0,
222+
nonce=nonce,
216223
balance=amount,
217224
)
225+
if nonce > 0:
226+
eoa.nonce = nonce
218227
else:
219228
# Type-4 transaction is sent to the EOA to set the storage, so the nonce must be 1
220229
if not isinstance(delegation, Address) and delegation == "Self":
221230
delegation = eoa
231+
nonce = Number(1 if nonce is None else nonce)
222232
account = Account(
223-
nonce=1,
233+
nonce=nonce,
224234
balance=amount,
225235
storage=storage if storage is not None else {},
226236
code=DELEGATION_DESIGNATION + bytes(delegation) # type: ignore
227237
if delegation is not None
228238
else b"",
229239
)
230-
eoa.nonce = Number(1)
240+
eoa.nonce = nonce
231241

232242
super().__setitem__(eoa, account)
233243
return eoa

0 commit comments

Comments
 (0)