|
29 | 29 |
|
30 | 30 | import pytest |
31 | 31 | from execution_testing import ( |
32 | | - DETERMINISTIC_DEPLOYMENT_CONTRACT_ADDRESS, |
| 32 | + DETERMINISTIC_FACTORY_ADDRESS, |
33 | 33 | EOA, |
34 | 34 | Account, |
35 | 35 | Address, |
36 | 36 | Alloc, |
37 | 37 | Block, |
38 | 38 | BlockchainTestFiller, |
| 39 | + Bytecode, |
39 | 40 | Bytes, |
40 | 41 | Fork, |
41 | 42 | Hash, |
@@ -143,46 +144,51 @@ def load(cls, storage_depth: int, account_depth: int) -> Self: |
143 | 144 | return cls.model_validate_json(get_mined_asset(json_filename)) |
144 | 145 |
|
145 | 146 |
|
146 | | -ATTACK_ORCHESTRATOR_BYTECODE = ( |
147 | | - # - Prepare CREATE2 Address Keccak, Mem[0:85] |
148 | | - # Mem[0:21] = 0xff + DETERMINISTIC_DEPLOYMENT_CONTRACT_ADDRESS |
149 | | - Op.MSTORE( |
150 | | - 0, |
151 | | - Hash( |
152 | | - b"\xff" + DETERMINISTIC_DEPLOYMENT_CONTRACT_ADDRESS, |
153 | | - right_padding=True, |
154 | | - ), |
155 | | - ) |
156 | | - # Mem[21:53] = salt (Batch start) |
157 | | - + Op.MSTORE(1 + 20, Op.CALLDATALOAD(32)) |
158 | | - # Mem[53:85] = Initcode hash |
159 | | - + Op.MSTORE(1 + 20 + 32, Op.CALLDATALOAD(96)) |
160 | | - # - Prepare ERC20 Calldata, Mem[85:121] |
161 | | - # Mem[85:89] = 0x64dd891a (ABI `attack(uint256)`) |
162 | | - + Op.MSTORE( |
163 | | - 1 + 20 + 32 + 32, |
164 | | - Hash(bytes.fromhex("64dd891a"), right_padding=True), |
| 147 | +def attack_orchestrator_bytecode(fork: Fork) -> Bytecode: |
| 148 | + """ |
| 149 | + Return the bytecode of the attack orchestrator, depending on the fork. |
| 150 | + """ |
| 151 | + factory_address = ( |
| 152 | + fork.deterministic_factory_predeploy_address() |
| 153 | + or DETERMINISTIC_FACTORY_ADDRESS |
165 | 154 | ) |
166 | | - # Mem[89:121] = value |
167 | | - + Op.MSTORE(1 + 20 + 32 + 32 + 4, Op.CALLDATALOAD(0)) |
168 | | - + While( |
169 | | - body=Op.POP( |
170 | | - Op.CALL( |
171 | | - address=Op.AND(2 ** (20 * 8) - 1, Op.SHA3(0, 85)), |
172 | | - args_offset=1 + 20 + 32 + 32, |
173 | | - args_size=4 + 32, |
| 155 | + return ( |
| 156 | + # - Prepare CREATE2 Address Keccak, Mem[0:85] |
| 157 | + # Mem[0:21] = 0xff + DETERMINISTIC_FACTORY_ADDRESS |
| 158 | + Op.MSTORE( |
| 159 | + 0, |
| 160 | + Hash( |
| 161 | + b"\xff" + factory_address, |
| 162 | + right_padding=True, |
| 163 | + ), |
| 164 | + ) |
| 165 | + # Mem[21:53] = salt (Batch start) |
| 166 | + + Op.MSTORE(1 + 20, Op.CALLDATALOAD(32)) |
| 167 | + # Mem[53:85] = Initcode hash |
| 168 | + + Op.MSTORE(1 + 20 + 32, Op.CALLDATALOAD(96)) |
| 169 | + # - Prepare ERC20 Calldata, Mem[85:121] |
| 170 | + # Mem[85:89] = 0x64dd891a (ABI `attack(uint256)`) |
| 171 | + + Op.MSTORE( |
| 172 | + 1 + 20 + 32 + 32, |
| 173 | + Hash(bytes.fromhex("64dd891a"), right_padding=True), |
| 174 | + ) |
| 175 | + # Mem[89:121] = value |
| 176 | + + Op.MSTORE(1 + 20 + 32 + 32 + 4, Op.CALLDATALOAD(0)) |
| 177 | + + While( |
| 178 | + body=Op.POP( |
| 179 | + Op.CALL( |
| 180 | + address=Op.AND(2 ** (20 * 8) - 1, Op.SHA3(0, 85)), |
| 181 | + args_offset=1 + 20 + 32 + 32, |
| 182 | + args_size=4 + 32, |
| 183 | + ) |
174 | 184 | ) |
| 185 | + # Increment salt in memory by one |
| 186 | + + Op.MSTORE(1 + 20, Op.ADD(1, Op.MLOAD(1 + 20))), |
| 187 | + # Check that current salt is less than or equal to batch end |
| 188 | + condition=Op.LT(Op.MLOAD(1 + 20), Op.ADD(1, Op.CALLDATALOAD(64))), |
175 | 189 | ) |
176 | | - # Increment salt in memory by one |
177 | | - + Op.MSTORE(1 + 20, Op.ADD(1, Op.MLOAD(1 + 20))), |
178 | | - # Check that current salt is less than or equal to batch end |
179 | | - condition=Op.LT(Op.MLOAD(1 + 20), Op.ADD(1, Op.CALLDATALOAD(64))), |
| 190 | + + Op.STOP |
180 | 191 | ) |
181 | | - + Op.STOP |
182 | | -) |
183 | | -ATTACK_ORCHESTRATOR_ADDRESS = compute_deterministic_create2_address( |
184 | | - Hash(0), Initcode(deploy_code=ATTACK_ORCHESTRATOR_BYTECODE) |
185 | | -) |
186 | 192 |
|
187 | 193 |
|
188 | 194 | class Attack(BaseModel): |
@@ -285,8 +291,13 @@ def calculate_tx_gas_limit(self, fork: Fork) -> int: |
285 | 291 |
|
286 | 292 | def generate_transaction(self, fork: Fork, sender: EOA) -> Transaction: |
287 | 293 | """Generate the transaction to perform the attack.""" |
| 294 | + attack_orchestrator_address = compute_deterministic_create2_address( |
| 295 | + salt=Hash(0), |
| 296 | + initcode=Initcode(deploy_code=attack_orchestrator_bytecode(fork)), |
| 297 | + fork=fork, |
| 298 | + ) |
288 | 299 | return Transaction( |
289 | | - to=ATTACK_ORCHESTRATOR_ADDRESS, |
| 300 | + to=attack_orchestrator_address, |
290 | 301 | gas_limit=self.calculate_tx_gas_limit(fork), |
291 | 302 | sender=sender, |
292 | 303 | data=self.calldata(), |
@@ -357,11 +368,7 @@ def test_worst_depth_stateroot_recomp( |
357 | 368 |
|
358 | 369 | # Deploy orchestrator to deterministic address |
359 | 370 | orchestrator_address = pre.deterministic_deploy_contract( |
360 | | - deploy_code=ATTACK_ORCHESTRATOR_BYTECODE |
361 | | - ) |
362 | | - assert orchestrator_address == ATTACK_ORCHESTRATOR_ADDRESS, ( |
363 | | - f"Orchestrator address mismatch: {orchestrator_address} != " |
364 | | - f"{ATTACK_ORCHESTRATOR_ADDRESS}" |
| 371 | + deploy_code=attack_orchestrator_bytecode(fork) |
365 | 372 | ) |
366 | 373 | print(f" Orchestrator will be deployed at: {orchestrator_address}") |
367 | 374 |
|
|
0 commit comments