Skip to content

Commit 98cf1a8

Browse files
feat(tests): ckzg functions for peerdas tests (#1614)
* added kzg functions for peerdas tests * fix: use proofs only instead of full cells * tests passing except for third one, too much gas (nethermind) or too many blobs (7vs9, geth) * implemented feedback * function that loads trusted setup now has to return trusted setup otherwise it cant be used as input to function that requires trusted setup to be passed * removed debug print * added filelock for r/w blobs * removed logging changes from this PR * removed changes to conversions.py * fixes * fix * fixes --------- Co-authored-by: Mario Vega <marioevz@gmail.com>
1 parent d952142 commit 98cf1a8

File tree

16 files changed

+9063
-91
lines changed

16 files changed

+9063
-91
lines changed

docs/CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ Users can select any of the artifacts depending on their testing needs for their
5252

5353
#### `execute`
5454

55-
- ✨ Add `blob_transaction_test` execute test spec, which allows tests that send blob transactions to a running client and verifying its `engine_getBlobsVX` endpoint behavior ([#1644](https://github.com/ethereum/execution-spec-tests/pull/1644)).
55+
- ✨ Added new `Blob` class which can use the ckzg library to generate valid blobs at runtime ([#1614](https://github.com/ethereum/execution-spec-tests/pull/1614)).
56+
- ✨ Added `blob_transaction_test` execute test spec, which allows tests that send blob transactions to a running client and verifying its `engine_getBlobsVX` endpoint behavior ([#1644](https://github.com/ethereum/execution-spec-tests/pull/1644)).
5657

5758
### 📋 Misc
5859

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ dependencies = [
5050
"pytest-regex>=0.2.0,<0.3",
5151
"eth-abi>=5.2.0",
5252
"joblib>=1.4.2",
53+
"ckzg>=2.1.1",
5354
]
5455

5556
[project.urls]

src/ethereum_test_execution/blob_transaction.py

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
"""Test execution format to get blobs from the execution client."""
22

3+
from hashlib import sha256
34
from typing import ClassVar, Dict, List
45

56
from ethereum_test_base_types import Hash
7+
from ethereum_test_base_types.base_types import Bytes
68
from ethereum_test_forks import Fork
79
from ethereum_test_rpc import BlobAndProofV1, BlobAndProofV2, EngineRPC, EthRPC
810
from ethereum_test_types import NetworkWrappedTransaction, Transaction
@@ -18,18 +20,19 @@ def versioned_hashes_with_blobs_and_proofs(
1820
proofs.
1921
"""
2022
versioned_hashes: Dict[Hash, BlobAndProofV1 | BlobAndProofV2] = {}
21-
for blob in tx.blobs:
22-
versioned_hash = blob.versioned_hash()
23-
if blob.kzg_proof is not None:
24-
versioned_hashes[versioned_hash] = BlobAndProofV1(blob=blob.data, proof=blob.kzg_proof)
25-
elif blob.kzg_cell_proofs is not None:
26-
versioned_hashes[versioned_hash] = BlobAndProofV2(
27-
blob=blob.data, proofs=blob.kzg_cell_proofs
23+
for blob in tx.blob_objects:
24+
if isinstance(blob.proof, Bytes):
25+
versioned_hashes[blob.versioned_hash] = BlobAndProofV1(
26+
blob=blob.data, proof=blob.proof
27+
)
28+
elif isinstance(blob.proof, list):
29+
versioned_hashes[blob.versioned_hash] = BlobAndProofV2(
30+
blob=blob.data, proofs=blob.proof
2831
)
2932
else:
3033
raise ValueError(
31-
f"Blob with versioned hash {versioned_hash.hex()} requires either kzg_proof "
32-
"or kzg_cell_proofs, but both are None"
34+
f"Blob with versioned hash {blob.versioned_hash.hex()} requires a proof "
35+
"that is not None"
3336
)
3437

3538
return versioned_hashes
@@ -96,7 +99,31 @@ def execute(self, fork: Fork, eth_rpc: EthRPC, engine_rpc: EngineRPC | None):
9699
if expected_blob.blob != received_blob.blob:
97100
raise ValueError("Blob mismatch.")
98101
if expected_blob.proofs != received_blob.proofs:
99-
raise ValueError("Proofs mismatch.")
102+
error_message = "Proofs mismatch."
103+
error_message += f"len(expected_blob.proofs) = {len(expected_blob.proofs)}, "
104+
error_message += f"len(received_blob.proofs) = {len(received_blob.proofs)}\n"
105+
if len(expected_blob.proofs) == len(received_blob.proofs):
106+
index = 0
107+
108+
for expected_proof, received_proof in zip(
109+
expected_blob.proofs, received_blob.proofs, strict=False
110+
):
111+
if len(expected_proof) != len(received_proof):
112+
error_message += f"Proof length mismatch. index = {index},"
113+
error_message += f"expected_proof length = {len(expected_proof)}, "
114+
error_message += f"received_proof length = {len(received_proof)}\n"
115+
index += 1
116+
continue
117+
if expected_proof != received_proof:
118+
error_message += f"Proof mismatch. index = {index},"
119+
error_message += (
120+
f"expected_proof hash = {sha256(expected_proof).hexdigest()}, "
121+
)
122+
error_message += (
123+
f"received_proof hash = {sha256(received_proof).hexdigest()}\n"
124+
)
125+
index += 1
126+
raise ValueError(error_message)
100127
else:
101128
raise ValueError(f"Unexpected blob type: {type(expected_blob)}")
102129

src/ethereum_test_forks/base_fork.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,20 @@
11
"""Abstract base class for Ethereum forks."""
22

33
from abc import ABC, ABCMeta, abstractmethod
4-
from typing import Any, ClassVar, List, Mapping, Optional, Protocol, Sized, Tuple, Type
4+
from typing import (
5+
Any,
6+
ClassVar,
7+
Dict,
8+
List,
9+
Literal,
10+
Mapping,
11+
Optional,
12+
Protocol,
13+
Sized,
14+
Tuple,
15+
Type,
16+
Union,
17+
)
518

619
from semver import Version
720

@@ -155,6 +168,14 @@ class BaseFork(ABC, metaclass=BaseForkMeta):
155168
_solc_name: ClassVar[Optional[str]] = None
156169
_ignore: ClassVar[bool] = False
157170

171+
# make mypy happy
172+
BLOB_CONSTANTS: ClassVar[Dict[str, Union[int, Literal["big"]]]] = {}
173+
174+
@classmethod
175+
def get_blob_constant(cls, name: str) -> int | Literal["big"]:
176+
"""Return value of requested blob constant."""
177+
raise NotImplementedError
178+
158179
def __init_subclass__(
159180
cls,
160181
*,

src/ethereum_test_forks/forks/forks.py

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from hashlib import sha256
55
from os.path import realpath
66
from pathlib import Path
7-
from typing import List, Mapping, Optional, Sized, Tuple
7+
from typing import List, Literal, Mapping, Optional, Sized, Tuple
88

99
from semver import Version
1010

@@ -908,6 +908,27 @@ def valid_opcodes(
908908
class Cancun(Shanghai):
909909
"""Cancun fork."""
910910

911+
BLOB_CONSTANTS = { # every value is an int or a Literal
912+
"FIELD_ELEMENTS_PER_BLOB": 4096,
913+
"BYTES_PER_FIELD_ELEMENT": 32,
914+
"CELL_LENGTH": 2048,
915+
"BLS_MODULUS": 0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000001, # EIP-2537: Main subgroup order = q, due to this BLS_MODULUS every blob byte (uint256) must be smaller than 116 # noqa: E501
916+
# https://github.com/ethereum/consensus-specs/blob/cc6996c22692d70e41b7a453d925172ee4b719ad/specs/deneb/polynomial-commitments.md?plain=1#L78
917+
"BYTES_PER_PROOF": 48,
918+
"BYTES_PER_COMMITMENT": 48,
919+
"KZG_ENDIANNESS": "big",
920+
"AMOUNT_CELL_PROOFS": 0,
921+
}
922+
923+
@classmethod
924+
def get_blob_constant(cls, name: str) -> int | Literal["big"]:
925+
"""Return blob constant if it exists."""
926+
retrieved_constant = cls.BLOB_CONSTANTS.get(name)
927+
assert retrieved_constant is not None, (
928+
f"You tried to retrieve the blob constant {name} but it does not exist!"
929+
)
930+
return retrieved_constant
931+
911932
@classmethod
912933
def solc_min_version(cls) -> Version:
913934
"""Return minimum version of solc that supports this fork."""
@@ -1092,6 +1113,16 @@ def valid_opcodes(
10921113
class Prague(Cancun):
10931114
"""Prague fork."""
10941115

1116+
# update some blob constants
1117+
BLOB_CONSTANTS = {
1118+
**Cancun.BLOB_CONSTANTS, # same base constants as cancun
1119+
"MAX_BLOBS_PER_BLOCK": 9, # but overwrite or add these
1120+
"TARGET_BLOBS_PER_BLOCK": 6,
1121+
"MAX_BLOB_GAS_PER_BLOCK": 1179648,
1122+
"TARGET_BLOB_GAS_PER_BLOCK": 786432,
1123+
"BLOB_BASE_FEE_UPDATE_FRACTION": 5007716,
1124+
}
1125+
10951126
@classmethod
10961127
def is_deployed(cls) -> bool:
10971128
"""
@@ -1343,6 +1374,12 @@ def engine_forkchoice_updated_version(
13431374
class Osaka(Prague, solc_name="cancun"):
13441375
"""Osaka fork."""
13451376

1377+
# update some blob constants
1378+
BLOB_CONSTANTS = {
1379+
**Prague.BLOB_CONSTANTS, # same base constants as prague
1380+
"AMOUNT_CELL_PROOFS": 128,
1381+
}
1382+
13461383
@classmethod
13471384
def engine_get_payload_version(
13481385
cls, block_number: int = 0, timestamp: int = 0

src/ethereum_test_rpc/types.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,14 +152,14 @@ def blob_versioned_hashes(self, versioned_hash_version: int = 1) -> List[Hash]:
152152

153153

154154
class BlobAndProofV1(CamelModel):
155-
"""Represents a blob and single-proof structure."""
155+
"""Represents a blob and single-proof structure (< Osaka)."""
156156

157157
blob: Bytes
158158
proof: Bytes
159159

160160

161161
class BlobAndProofV2(CamelModel):
162-
"""Represents a blob and proof structure."""
162+
"""Represents a blob and cell proof structure (>= Osaka)."""
163163

164164
blob: Bytes
165165
proofs: List[Bytes]

src/ethereum_test_types/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""Common definitions and types."""
22

33
from .account_types import EOA, Alloc
4+
from .blob_types import Blob
45
from .block_types import (
56
Environment,
67
EnvironmentDefaults,
@@ -23,7 +24,6 @@
2324
)
2425
from .transaction_types import (
2526
AuthorizationTuple,
26-
Blob,
2727
NetworkWrappedTransaction,
2828
Transaction,
2929
TransactionDefaults,

0 commit comments

Comments
 (0)