35
35
36
36
def deploy_initcode_template (pre : Alloc , fork : Fork ) -> tuple [Address , Bytecode ]:
37
37
"""Deploy the initcode template contract."""
38
- # The initcode will take its address as a starting point to the input to the keccak
39
- # hash function.
40
- # It will reuse the output of the hash function in a loop to create a large amount of
41
- # seemingly random code, until it reaches the maximum contract size.
38
+ # The initcode will take its address as a starting point to the input to
39
+ # the keccak hash function.
40
+ # It will reuse the output of the hash function in a loop to create a
41
+ # large amount of random code, until it reaches the maximum code size.
42
42
initcode = (
43
43
Op .MSTORE (0 , Op .ADDRESS )
44
44
+ While (
@@ -65,8 +65,8 @@ def deploy_initcode_template(pre: Alloc, fork: Fork) -> tuple[Address, Bytecode]
65
65
66
66
def deploy_factory_contract (pre : Alloc , fork : Fork , initcode_address : Address ) -> Address :
67
67
"""Deploy the factory contract."""
68
- # The factory contract will simply use the initcode that is already deployed,
69
- # and create a new contract and return its address if successful.
68
+ # The factory contract will use the initcode that is already
69
+ # deployed, and create a new contract and return its address if successful.
70
70
factory_code = (
71
71
Op .EXTCODECOPY (
72
72
address = initcode_address ,
@@ -91,8 +91,8 @@ def deploy_factory_contract(pre: Alloc, fork: Fork, initcode_address: Address) -
91
91
92
92
def deploy_factory_caller_contract (pre : Alloc , fork : Fork , factory_address : Address ) -> Address :
93
93
"""Deploy the factory caller contract."""
94
- # The factory caller will call the factory contract N times, creating N new contracts.
95
- # Calldata should contain the N value.
94
+ # The factory caller will call the factory contract N times, creating N
95
+ # new contracts. Calldata should contain the N value.
96
96
factory_caller_code = Op .CALLDATALOAD (0 ) + While (
97
97
body = Op .POP (Op .CALL (address = factory_address )),
98
98
condition = Op .PUSH1 (1 ) + Op .SWAP1 + Op .SUB + Op .DUP1 + Op .ISZERO + Op .ISZERO ,
@@ -114,7 +114,10 @@ def deploy_attack_contract(
114
114
+ Op .MSTORE (64 , initcode .keccak256 ())
115
115
)
116
116
117
- # setup_cost: G_VERY_LOW * 9 (PUSH) + G_VERY_LOW * 3 (MSTORE) + G_VERY_LOW (CALLDATACOPY)
117
+ # setup_cost:
118
+ # G_VERY_LOW * 9 (PUSH) +
119
+ # G_VERY_LOW * 3 (MSTORE) +
120
+ # G_VERY_LOW (CALLDATACOPY)
118
121
119
122
# Attack call
120
123
attack_call = Bytecode ()
@@ -131,7 +134,7 @@ def deploy_attack_contract(
131
134
132
135
# loop_cost = (
133
136
# gas_costs.G_KECCAK_256 KECCAK static cost
134
- # + math.ceil(85 / 32) * gas_costs.G_KECCAK_256_WORD KECCAK dynamic cost for CREATE2
137
+ # + math.ceil(85 / 32) * gas_costs.G_KECCAK_256_WORD
135
138
# + gas_costs.G_VERY_LOW * ~MSTOREs+ADDs
136
139
# + gas_costs.G_COLD_ACCOUNT_ACCESS Opcode cost
137
140
# + 30 ~Gluing opcodes
@@ -162,24 +165,28 @@ def test_worst_bytecode_single_opcode(
162
165
tx_gas_limit_cap : int ,
163
166
):
164
167
"""
165
- Test a block execution where a single opcode execution maxes out the gas limit,
168
+ Test a block execution where a single opcode execution maxes out the
169
+ gas limit,
166
170
and the opcodes access a huge amount of contract code.
167
171
168
- We first use a single block to deploy a factory contract that will be used to deploy
172
+ We first use a single block to deploy a factory contract that will be
173
+ used to deploy
169
174
a large number of contracts.
170
175
171
176
This is done to avoid having a big pre-allocation size for the test.
172
177
173
- The test is performed in the last block of the test, and the entire block gas limit is
178
+ The test is performed in the last block of the test, and the entire
179
+ block gas limit is
174
180
consumed by repeated opcode executions.
175
181
"""
176
182
iteration_count = gas_benchmark_value // tx_gas_limit_cap
177
183
178
184
# The attack gas limit is the gas limit which the target tx will use
179
- # The test will scale the block gas limit to setup the contracts accordingly to be
180
- # able to pay for the contract deposit. This has to take into account the 200 gas per byte,
181
- # but also the quadratic memory expansion costs which have to be paid each time the
182
- # memory is being setup
185
+ # The test will scale the block gas limit to setup the contracts
186
+ # accordingly to be able to pay for the contract deposit.
187
+ # This has to take into account the 200 gas per byte,
188
+ # but also the quadratic memory expansion costs which have to be paid
189
+ # each time the memory is being setup
183
190
max_contract_size = fork .max_code_size ()
184
191
185
192
gas_costs = fork .gas_costs ()
@@ -200,7 +207,8 @@ def test_worst_bytecode_single_opcode(
200
207
for _ in range (iteration_count ):
201
208
gas_available = min (tx_gas_limit_cap , gas_remaining )
202
209
total_contracts += (
203
- # Base available gas = GAS_LIMIT - intrinsic - (out of loop MSTOREs)
210
+ # Base available gas =
211
+ # GAS_LIMIT - intrinsic - (out of loop MSTOREs)
204
212
gas_available - intrinsic_gas_cost_calc () - setup_cost
205
213
) // loop_cost
206
214
gas_remaining -= gas_available
@@ -213,7 +221,8 @@ def test_worst_bytecode_single_opcode(
213
221
# Deployment Phase - Deploy N contracts
214
222
215
223
# Calculate the absolute minimum gas costs to deploy the contract
216
- # This does not take into account setting up the actual memory (using KECCAK256 and XOR)
224
+ # This does not take into account setting up the actual memory
225
+ # (using KECCAK256 and XOR)
217
226
# so the actual costs of deploying the contract is higher
218
227
memory_expansion_gas_calculator = fork .memory_expansion_gas_calculator ()
219
228
memory_gas_minimum = memory_expansion_gas_calculator (new_bytes = len (bytes (max_contract_size )))
0 commit comments