55Large proofs are created by deploying contracts with
66maximum allowed bytecode.
77
8- These proofs are then "ingested" by an opcode or precompile.
9-
10- First, the tests compute the "ingestion cost" for the proof.
11- Next, they attempt to ingest the maximum possible number of
12- proofs in a block with a given gas limit.
8+ Then, a pacman contract consumes (ᗧ•••) the maximum possible number of
9+ proofs in a block with a given gas limit using an opcode or precompile.
1310"""
1411
15- from typing import List
12+ from dataclasses import dataclass
13+ from typing import Callable
1614
1715import pytest
1816
19- from ethereum_test_forks import Fork
2017from ethereum_test_tools import (
2118 Address ,
2219 Alloc ,
2320 Block ,
2421 BlockchainTestFiller ,
22+ Bytecode ,
2523 Environment ,
2624 Transaction ,
2725)
3028REFERENCE_SPEC_GIT_PATH = "TODO"
3129REFERENCE_SPEC_VERSION = "TODO"
3230
33-
3431##############################
3532# #
3633# Config #
3734# #
3835##############################
39- GAS_LIMITS = [
40- 30_000_000 ,
41- ]
42- KiB = 1024
43- CONTRACT_BYTECODE_MAX_SIZE = 24 * KiB
44-
45-
46- ##############################
47- # #
48- # Test Helpers #
49- # #
50- ##############################
51- def get_proofs (pre : Alloc , proof_count : int ) -> List [Address ]:
52- """
53- Generate a list of proof addresses by deploying contracts
54- with maximum allowed bytecode size.
55- """
56- proofs = []
57- for i in range (proof_count ):
58- code = Op .JUMPDEST * (CONTRACT_BYTECODE_MAX_SIZE - 1 - 10 ) + Op .PUSH10 (i )
59- proofs .append (pre .deploy_contract (code = code ))
60- return proofs
61-
62-
63- def get_proof_eater (pre : Alloc , proof_count : int ) -> Address :
64- """Generate a proof eater contract that ingests a given proofs."""
65- proofs = get_proofs (pre , proof_count )
66- code = sum ([Op .EXTCODESIZE (proofs [i ]) for i in range (proof_count )])
67- return pre .deploy_contract (code = code )
36+ CONTRACT_BYTECODE_MAX_SIZE = 24 * 1024 # 24 KiB
37+ GAS_LIMITS = [30_000_000 , 60_000_000 , 100_000_000 , 300_000_000 ]
38+
39+
40+ @dataclass
41+ class OpcodeConfig :
42+ """Configuration for an opcode's proof eating behavior."""
43+
44+ gas_cost : int
45+ generate_bytecode : Callable [[Address ], Bytecode ]
46+
47+ def create_pacman (self , pre : Alloc , gas_limit : int ) -> Address :
48+ """
49+ Generate a pacman contract that ingests proofs using this opcode.
50+ ᗧ••• nom nom nom.
51+ """
52+ proof_count = (gas_limit - 21_000 ) // self .gas_cost
53+ proof_count = 5 # TODO: REMOVE THIS LIMIT
54+
55+ # Generate proofs
56+ proofs = [
57+ pre .deploy_contract (
58+ code = Op .JUMPDEST * (CONTRACT_BYTECODE_MAX_SIZE - 11 ) + Op .PUSH10 (i )
59+ )
60+ for i in range (proof_count )
61+ ]
62+
63+ # Generate bytecode using the opcode's configuration
64+ code = sum (self .generate_bytecode (proof ) for proof in proofs )
65+ return pre .deploy_contract (code = code )
66+
67+
68+ # Map opcodes to their configurations
69+ OPCODE_CONFIGS = {
70+ Op .EXTCODEHASH : OpcodeConfig (
71+ gas_cost = 2603 , # PUSH20[3] + EXTCODEHASH[2600]
72+ generate_bytecode = lambda addr : Op .EXTCODEHASH (addr ),
73+ ),
74+ Op .EXTCODESIZE : OpcodeConfig (
75+ gas_cost = 2603 , # PUSH20[3] + EXTCODESIZE[2600]
76+ generate_bytecode = lambda addr : Op .EXTCODESIZE (addr ),
77+ ),
78+ }
6879
6980
7081##############################
@@ -75,28 +86,18 @@ def get_proof_eater(pre: Alloc, proof_count: int) -> Address:
7586@pytest .mark .zkevm
7687@pytest .mark .valid_from ("Cancun" )
7788@pytest .mark .parametrize ("gas_limit" , GAS_LIMITS )
78- @pytest .mark .parametrize (
79- "num_called_contracts" ,
80- [
81- 1 ,
82- # 10,
83- # MAX_NUM_CONTRACT_CALLS
84- ],
85- )
89+ @pytest .mark .parametrize ("opcode" , OPCODE_CONFIGS .keys (), ids = str )
8690def test_via_opcode (
8791 blockchain_test : BlockchainTestFiller ,
8892 pre : Alloc ,
89- fork : Fork ,
9093 gas_limit : int ,
91- num_called_contracts : int ,
94+ opcode : Op ,
9295):
9396 """Test zkEVM proof size limits using a specific opcode."""
94- env = Environment (gas_limit = gas_limit )
95-
96- # MAX_NUM_CONTRACT_CALLS = (gas_limit - 21_000) // (3 + 2600)
97+ config = OPCODE_CONFIGS [opcode ]
9798
9899 tx = Transaction (
99- to = get_proof_eater (pre , num_called_contracts ),
100+ to = config . create_pacman (pre , gas_limit ),
100101 gas_limit = gas_limit ,
101102 gas_price = 10 ,
102103 sender = pre .fund_eoa (),
@@ -105,7 +106,7 @@ def test_via_opcode(
105106 )
106107
107108 blockchain_test (
108- env = env ,
109+ env = Environment ( gas_limit = gas_limit ) ,
109110 pre = pre ,
110111 post = {},
111112 blocks = [Block (txs = [tx ])],
0 commit comments