Skip to content

Commit 0f188fe

Browse files
authored
feat: add mainnet tests for osaka (#1806)
* feat: add mainnet tests * fix: check early whether eoa can afford eoa-fund-amount-default and also reduce its default from 1 eth to 0.1 eth
1 parent 51cfd90 commit 0f188fe

File tree

5 files changed

+254
-6
lines changed

5 files changed

+254
-6
lines changed

packages/testing/src/execution_testing/cli/pytest_commands/plugins/execute/pre_alloc.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ def pytest_addoption(parser: pytest.Parser) -> None:
116116
"--eoa-fund-amount-default",
117117
action="store",
118118
dest="eoa_fund_amount_default",
119-
default=10**18,
119+
default=10**17,
120120
type=int,
121121
help="The default amount of wei to fund each EOA in each test with.",
122122
)

packages/testing/src/execution_testing/cli/pytest_commands/plugins/execute/sender.py

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def pytest_addoption(parser: pytest.Parser) -> None:
2525
dest="seed_account_sweep_amount",
2626
type=Wei,
2727
default=None,
28-
help="Amount of wei to sweep from the seed account to the sender account. "
28+
help="Amount of wei to sweep from the seed account to the sender account. " # noqa: E501
2929
"Default=None (Entire balance)",
3030
)
3131

@@ -36,7 +36,7 @@ def pytest_addoption(parser: pytest.Parser) -> None:
3636
type=Wei,
3737
default=None,
3838
help=(
39-
"Gas price set for the funding transactions of each worker's sender key."
39+
"Gas price set for the funding transactions of each worker's sender key." # noqa: E501
4040
),
4141
)
4242

@@ -47,7 +47,7 @@ def pytest_addoption(parser: pytest.Parser) -> None:
4747
type=Wei,
4848
default=21_000,
4949
help=(
50-
"Gas limit set for the funding transactions of each worker's sender key."
50+
"Gas limit set for the funding transactions of each worker's sender key." # noqa: E501
5151
),
5252
)
5353

@@ -80,6 +80,7 @@ def seed_account_sweep_amount(request: pytest.FixtureRequest) -> int | None:
8080

8181
@pytest.fixture(scope="session")
8282
def sender_key_initial_balance(
83+
request: pytest.FixtureRequest,
8384
seed_sender: EOA,
8485
eth_rpc: EthRPC,
8586
session_temp_folder: Path,
@@ -127,6 +128,31 @@ def sender_key_initial_balance(
127128
* sender_funding_transactions_gas_price
128129
)
129130

131+
# ensure sender has enough balance for eoa_fund_amount_default
132+
eoa_fund_amount_default: int = (
133+
request.config.option.eoa_fund_amount_default
134+
)
135+
# Reserve gas for funding tx (21000 gas * gas_price)
136+
funding_tx_cost = (
137+
sender_fund_refund_gas_limit
138+
* sender_funding_transactions_gas_price
139+
)
140+
if (
141+
sender_key_initial_balance
142+
< eoa_fund_amount_default + funding_tx_cost
143+
):
144+
raise ValueError(
145+
f"Seed sender balance too low for --eoa-fund-amount-default=" # noqa: E501
146+
f"{eoa_fund_amount_default}. "
147+
f"Available balance per worker: {sender_key_initial_balance} wei " # noqa: E501
148+
f"({sender_key_initial_balance / 10**18:.6f} ETH). "
149+
f"Required: {eoa_fund_amount_default + funding_tx_cost} wei " # noqa: E501
150+
f"({(eoa_fund_amount_default + funding_tx_cost) / 10**18:.6f} ETH). " # noqa: E501
151+
f"Either fund the seed account with more ETH or use "
152+
f"--eoa-fund-amount-default={sender_key_initial_balance - funding_tx_cost} " # noqa: E501
153+
f"or lower."
154+
)
155+
130156
with base_file.open("w") as f:
131157
f.write(str(sender_key_initial_balance))
132158
return sender_key_initial_balance

packages/testing/src/execution_testing/rpc/rpc.py

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ def post_request(
188188
"RPC response didn't contain a result field"
189189
)
190190
result = response_json["result"]
191+
logger.info(f"RPC Result: {result}")
191192
return result
192193

193194

@@ -239,6 +240,7 @@ def config(self, timeout: int | None = None) -> EthConfigResponse | None:
239240
client.
240241
"""
241242
try:
243+
logger.info("Requesting eth_config..")
242244
response = self.post_request(method="config", timeout=timeout)
243245
if response is None:
244246
logger.warning("eth_config request: failed to get response")
@@ -257,6 +259,7 @@ def config(self, timeout: int | None = None) -> EthConfigResponse | None:
257259

258260
def chain_id(self) -> int:
259261
"""`eth_chainId`: Returns the current chain id."""
262+
logger.info("Requesting chainid of provided RPC endpoint..")
260263
response = self.post_request(method="chainId", timeout=10)
261264
return int(response, 16)
262265

@@ -272,6 +275,7 @@ def get_block_by_number(
272275
if isinstance(block_number, int)
273276
else block_number
274277
)
278+
logger.info(f"Requesting info about block {block}..")
275279
params = [block, full_txs]
276280
response = self.post_request(method="getBlockByNumber", params=params)
277281
return response
@@ -280,6 +284,7 @@ def get_block_by_hash(
280284
self, block_hash: Hash, full_txs: bool = True
281285
) -> Any | None:
282286
"""`eth_getBlockByHash`: Returns information about a block by hash."""
287+
logger.info(f"Requesting block info of {block_hash}..")
283288
params = [f"{block_hash}", full_txs]
284289
response = self.post_request(method="getBlockByHash", params=params)
285290
return response
@@ -295,6 +300,7 @@ def get_balance(
295300
if isinstance(block_number, int)
296301
else block_number
297302
)
303+
logger.info(f"Requesting balance of {address} at block {block}")
298304
params = [f"{address}", block]
299305
response = self.post_request(method="getBalance", params=params)
300306
return int(response, 16)
@@ -308,6 +314,7 @@ def get_code(
308314
if isinstance(block_number, int)
309315
else block_number
310316
)
317+
logger.info(f"Requesting code of {address} at block {block}")
311318
params = [f"{address}", block]
312319
response = self.post_request(method="getCode", params=params)
313320
return Bytes(response)
@@ -324,6 +331,7 @@ def get_transaction_count(
324331
if isinstance(block_number, int)
325332
else block_number
326333
)
334+
logger.info(f"Requesting nonce of {address}")
327335
params = [f"{address}", block]
328336
response = self.post_request(
329337
method="getTransactionCount", params=params
@@ -335,6 +343,7 @@ def get_transaction_by_hash(
335343
) -> TransactionByHashResponse | None:
336344
"""`eth_getTransactionByHash`: Returns transaction details."""
337345
try:
346+
logger.info(f"Requesting tx details of {transaction_hash}")
338347
response = self.post_request(
339348
method="getTransactionByHash", params=[f"{transaction_hash}"]
340349
)
@@ -356,6 +365,7 @@ def get_transaction_receipt(
356365
Used to get the actual gas used by a transaction for gas validation
357366
in benchmark tests.
358367
"""
368+
logger.info(f"Requesting tx receipt of {transaction_hash}")
359369
response = self.post_request(
360370
method="getTransactionReceipt", params=[f"{transaction_hash}"]
361371
)
@@ -376,15 +386,19 @@ def get_storage_at(
376386
if isinstance(block_number, int)
377387
else block_number
378388
)
389+
logger.info(
390+
f"Requesting storage value mapped to key {position} "
391+
f"of contract {address}"
392+
)
379393
params = [f"{address}", f"{position}", block]
380394
response = self.post_request(method="getStorageAt", params=params)
381395
return Hash(response)
382396

383397
def gas_price(self) -> int:
384398
"""
385-
`eth_gasPrice`: Returns the number of transactions sent from an
386-
address.
399+
`eth_gasPrice`: Returns the gas price.
387400
"""
401+
logger.info("Requesting gas price")
388402
response = self.post_request(method="gasPrice")
389403
return int(response, 16)
390404

@@ -393,6 +407,7 @@ def send_raw_transaction(
393407
) -> Hash:
394408
"""`eth_sendRawTransaction`: Send a transaction to the client."""
395409
try:
410+
logger.info("Sending raw tx..")
396411
response = self.post_request(
397412
method="sendRawTransaction",
398413
params=[transaction_rlp.hex()],
@@ -402,6 +417,7 @@ def send_raw_transaction(
402417
assert result_hash is not None
403418
return result_hash
404419
except Exception as e:
420+
logger.error(e)
405421
raise SendTransactionExceptionError(
406422
str(e), tx_rlp=transaction_rlp
407423
) from e
@@ -410,6 +426,7 @@ def send_transaction(self, transaction: Transaction) -> Hash:
410426
"""`eth_sendRawTransaction`: Send a transaction to the client."""
411427
# TODO: is this a copypaste error from above?
412428
try:
429+
logger.info("Sending tx..")
413430
response = self.post_request(
414431
method="sendRawTransaction",
415432
params=[transaction.rlp().hex()],
@@ -455,6 +472,7 @@ def wait_for_transaction(
455472
tx_hash = transaction.hash
456473
start_time = time.time()
457474
while True:
475+
logger.info(f"Waiting for inclusion of tx {tx_hash} in a block..")
458476
tx = self.get_transaction_by_hash(tx_hash)
459477
if tx is not None and tx.block_number is not None:
460478
return tx
@@ -476,13 +494,17 @@ def wait_for_transactions(
476494
tx_hashes = [tx.hash for tx in transactions]
477495
responses: List[TransactionByHashResponse] = []
478496
start_time = time.time()
497+
logger.info("Waiting for all transaction to be included in a block..")
479498
while True:
480499
i = 0
481500
while i < len(tx_hashes):
482501
tx_hash = tx_hashes[i]
483502
tx = self.get_transaction_by_hash(tx_hash)
484503
if tx is not None and tx.block_number is not None:
485504
responses.append(tx)
505+
logger.info(
506+
f"Tx {tx} was included in block {tx.block_number}"
507+
)
486508
tx_hashes.pop(i)
487509
else:
488510
i += 1
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
"""
2+
Mainnet marked tests for EIP-7883 ModExp gas cost increase.
3+
4+
Tests for ModExp gas cost increase in
5+
[EIP-7883: ModExp Gas Cost Increase](https://eips.ethereum.org/EIPS/eip-7883).
6+
"""
7+
8+
from typing import Dict
9+
10+
import pytest
11+
from execution_testing import (
12+
Alloc,
13+
StateTestFiller,
14+
Transaction,
15+
)
16+
17+
from ...byzantium.eip198_modexp_precompile.helpers import ModExpInput
18+
from .spec import Spec, ref_spec_7883
19+
20+
REFERENCE_SPEC_GIT_PATH = ref_spec_7883.git_path
21+
REFERENCE_SPEC_VERSION = ref_spec_7883.version
22+
23+
pytestmark = [pytest.mark.valid_at("Osaka"), pytest.mark.mainnet]
24+
25+
26+
@pytest.mark.parametrize(
27+
"modexp_input,modexp_expected",
28+
[
29+
pytest.param(
30+
ModExpInput(
31+
base="ff" * 31 + "fc",
32+
exponent="02",
33+
modulus="05",
34+
declared_base_length=32,
35+
declared_exponent_length=1,
36+
declared_modulus_length=1,
37+
),
38+
# expected result:
39+
bytes.fromhex("04"),
40+
id="32-bytes-long-base",
41+
),
42+
pytest.param(
43+
ModExpInput(
44+
base="ff" * 32 + "fb",
45+
exponent="02",
46+
modulus="05",
47+
declared_base_length=33,
48+
declared_exponent_length=1,
49+
declared_modulus_length=1,
50+
),
51+
# expected result:
52+
bytes.fromhex("01"),
53+
id="33-bytes-long-base", # higher cost than 32 bytes
54+
),
55+
pytest.param(
56+
ModExpInput(
57+
base="ee" * 32,
58+
exponent="ff" * Spec.MAX_LENGTH_BYTES, # 1024 is upper limit
59+
modulus="03",
60+
declared_base_length=32,
61+
declared_exponent_length=1024,
62+
declared_modulus_length=1,
63+
),
64+
# expected result:
65+
bytes.fromhex("02"),
66+
id="1024-bytes-long-exp",
67+
),
68+
pytest.param(
69+
ModExpInput(
70+
base="e09ad9675465c53a109fac66a445c91b292d2bb2c5268addb30cd82f80fcb0033ff97c80a5fc6f39193ae969c6ede6710a6b7ac27078a06d90ef1c72e5c85fb5",
71+
exponent="010001",
72+
modulus="fc9e1f6beb81516545975218075ec2af118cd8798df6e08a147c60fd6095ac2bb02c2908cf4dd7c81f11c289e4bce98f3553768f392a80ce22bf5c4f4a248c6b",
73+
declared_base_length=64,
74+
declared_exponent_length=3,
75+
declared_modulus_length=64,
76+
),
77+
# expected result:
78+
bytes.fromhex(
79+
"c36d804180c35d4426b57b50c5bfcca5c01856d104564cd513b461d3c8b8409128a5573e416d0ebe38f5f736766d9dc27143e4da981dfa4d67f7dc474cbee6d2"
80+
),
81+
id="nagydani-1-pow0x10001",
82+
),
83+
pytest.param(
84+
ModExpInput(
85+
base="8d74b1229cc36912165d7ed62334d5ce0683ad12dbade86cdbd705f46693d6c0",
86+
exponent="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
87+
modulus="8f70e8f94c5ad28ed971e258ea3854ebf57131ae4c842e5cafe1c70db8272caf",
88+
declared_base_length=32,
89+
declared_exponent_length=64,
90+
declared_modulus_length=32,
91+
),
92+
# expected result:
93+
bytes.fromhex(
94+
"0000000000000000000000000000000000000000000000000000000000000001"
95+
),
96+
id="zero-exponent-64bytes",
97+
),
98+
],
99+
)
100+
def test_modexp_different_base_lengths(
101+
state_test: StateTestFiller,
102+
pre: Alloc,
103+
tx: Transaction,
104+
post: Dict,
105+
modexp_input: ModExpInput,
106+
modexp_expected: ModExpInput,
107+
) -> None:
108+
"""Mainnet test for triggering gas cost increase."""
109+
state_test(pre=pre, tx=tx, post=post)

0 commit comments

Comments
 (0)