Skip to content

Commit a862f76

Browse files
committed
refactor(benchmark): enhance CREATE2 factory deployment and testing
- Updated the deploy_create2_factory_refactored.py script to improve the deployment of a CREATE2 factory with an initcode template, allowing for dynamic contract address generation. - Modified test_bloatnet.py to support on-the-fly CREATE2 address generation, optimizing gas costs and improving test accuracy. - Adjusted gas cost calculations in the README to reflect the new deployment approach, ensuring accurate benchmarks for BloatNet tests.
1 parent cf2c7c6 commit a862f76

File tree

3 files changed

+330
-229
lines changed

3 files changed

+330
-229
lines changed

tests/benchmark/bloatnet/README.md

Lines changed: 67 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,31 @@
22

33
## Overview
44

5-
The Bloatnet benchmarks work on the following fashion:
6-
1. They usually require a previously-deployed state (usually quite large) which the benchmarks
7-
will interact with.
8-
2. The deployment script helpers help deploying the required bytecode for the specific tests.
9-
3. The outputs of the deployment scripts get hardcoded into the codebase such that the benchmarks can interact with them.
5+
This README pretends to be a guide for any user that wants to run the bloatnet test/benchmark suite in any network.
6+
BloatNet bench cases can be seen in: https://hackmd.io/9icZeLN7R0Sk5mIjKlZAHQ.
7+
The idea of all these tests is to stress client implementations to find out where the limits of processing are focusing specifically on state-related operations.
8+
9+
In this document you will find a guide that will help you deploy all the setup contracts required by the benchmarks in `/benchmarks/bloatnet`.
1010

1111
## Gas Cost Constants
1212

1313
### BALANCE + EXTCODESIZE Pattern
14-
**Gas per contract: 2,707**
15-
- `PUSH20` (address): 3 gas
14+
**Gas per contract: ~2,772**
15+
- `SHA3` (CREATE2 address generation): 30 gas (static) + 18 gas (dynamic for 85 bytes)
1616
- `BALANCE` (cold access): 2,600 gas
1717
- `POP`: 2 gas
1818
- `EXTCODESIZE` (warm): 100 gas
1919
- `POP`: 2 gas
20+
- Memory operations and loop overhead: ~20 gas
2021

21-
### BALANCE + EXTCODECOPY(single-byte) Pattern
22-
**Gas per contract: ~2,710**
23-
- `PUSH20` (address): 3 gas
22+
### BALANCE + EXTCODECOPY(single-byte) Pattern
23+
**Gas per contract: ~2,775**
24+
- `SHA3` (CREATE2 address generation): 30 gas (static) + 18 gas (dynamic for 85 bytes)
2425
- `BALANCE` (cold access): 2,600 gas
2526
- `POP`: 2 gas
2627
- `EXTCODECOPY` (warm, 1 byte): 100 gas (base) + 3 gas (copy 1 byte)
27-
- `POP`: 2 gas
28+
- Memory operations: 4 gas
29+
- Loop overhead: ~20 gas
2830

2931
Note: Reading just 1 byte (specifically the last byte at offset 24575) forces the client
3032
to load the entire 24KB contract from disk while minimizing gas cost. This allows
@@ -35,103 +37,108 @@ targeting nearly as many contracts as the EXTCODESIZE pattern while forcing maxi
3537
### For BALANCE + EXTCODESIZE:
3638
| Gas Limit | Contracts Needed | Calculation |
3739
| --------- | ---------------- | ------------------- |
38-
| 5M | 1,838 | 5,000,000 ÷ 2,707 |
39-
| 50M | 18,380 | 50,000,000 ÷ 2,707 |
40-
| 150M | 55,403 | 150,000,000 ÷ 2,707 |
40+
| 1M | 352 | 1,000,000 ÷ 2,772 |
41+
| 5M | 1,769 | 5,000,000 ÷ 2,772 |
42+
| 50M | 17,690 | 50,000,000 ÷ 2,772 |
43+
| 150M | 53,071 | 150,000,000 ÷ 2,772 |
4144

42-
### For BALANCE + EXTCODECOPY (Optimized):
45+
### For BALANCE + EXTCODECOPY:
4346
| Gas Limit | Contracts Needed | Calculation |
4447
| --------- | ---------------- | ------------------- |
45-
| 5M | 1,845 | 5,000,000 ÷ 2,710 |
46-
| 50M | 18,450 | 50,000,000 ÷ 2,710 |
47-
| 150M | 55,350 | 150,000,000 ÷ 2,710 |
48+
| 1M | 352 | 1,000,000 ÷ 2,775 |
49+
| 5M | 1,768 | 5,000,000 ÷ 2,775 |
50+
| 50M | 17,684 | 50,000,000 ÷ 2,775 |
51+
| 150M | 53,053 | 150,000,000 ÷ 2,775 |
4852

49-
You can see the associated attack constants inside of the tests in `bloatnet/test_bloatnet.py`
53+
The CREATE2 address generation adds ~48 gas per contract but eliminates memory limitations in test framework.
5054

5155
## Quick Start: 150M Gas Attack
5256

53-
### 1. Deploy CREATE2 Factory (you can use an already deployed one if preferred and therefore, skip this step)
57+
### 1. Deploy CREATE2 Factory with Initcode Template
5458

5559
```bash
56-
# One-time setup - deploy the CREATE2 factory
57-
python3 tests/benchmark/bloatnet/deploy_create2_factory.py
60+
# Deploy the factory and initcode template (one-time setup)
61+
python3 tests/benchmark/bloatnet/deploy_create2_factory_refactored.py
5862

5963
# Output will show:
6064
# Factory deployed at: 0x... <-- Save this address
65+
# Init code hash: 0x... <-- Save this hash
6166
```
6267

6368
### 2. Deploy Contracts
6469

65-
The deployment script is interactive and will guide you through selecting the appropriate contract type for your benchmark.
66-
67-
#### Contract Types Available
68-
69-
1. **max_size_24kb**: 24KB contracts filled with unique bytecode (EXTCODE_ type of tests)
70-
2. **sload_heavy**: Contracts optimized for SLOAD benchmarking
71-
3. **storage_heavy**: Contracts with pre-initialized storage
72-
4. **custom**: Custom bytecode (for future extensions)
70+
Deploy contracts using the factory. Each contract will be unique due to ADDRESS-based randomness in the initcode.
7371

7472
#### Calculate Contracts Needed
7573

7674
Before running the deployment, calculate the number of contracts needed:
77-
- For 150M gas BALANCE+EXTCODESIZE: 55,403 contracts
78-
- For 150M gas BALANCE+EXTCODECOPY: 29,958 contracts
75+
- For 150M gas BALANCE+EXTCODESIZE: 53,071 contracts
76+
- For 150M gas BALANCE+EXTCODECOPY: 53,053 contracts
7977

8078
_Deploy enough contracts to cover the max gas you plan to use in your tests/benchmarks._
8179

8280
#### Running the Deployment
8381

8482
```bash
85-
# Run the interactive deployment script
86-
python3 tests/benchmark/bloatnet/deploy_bloatnet_simple.py \
87-
--num-contracts 55403 \
88-
--factory-address 0x... \ # Use factory address from step 1
89-
--max-code-size 24576 # Optional: specify max contract size (default: 24576)
83+
# Deploy contracts for 150M gas attack
84+
python3 tests/benchmark/bloatnet/deploy_create2_factory_refactored.py \
85+
--deploy-contracts 53100
86+
87+
# For smaller tests (e.g., 1M gas)
88+
python3 tests/benchmark/bloatnet/deploy_create2_factory_refactored.py \
89+
--deploy-contracts 370
9090
```
9191

9292
#### Deployment Output
9393

94-
After successful deployment, the script will:
94+
After successful deployment, the script will display:
9595

96-
1. Display the configuration needed for tests:
97-
```python
98-
=== Configuration for max_size_24kb tests ===
99-
CONTRACT_TYPE = "max_size_24kb"
100-
FACTORY_ADDRESS = Address("0x...")
101-
INIT_CODE_HASH = bytes.fromhex("...")
102-
NUM_DEPLOYED_CONTRACTS = 55403
103-
```
104-
105-
2. Save the configuration to a file:
10696
```
107-
Configuration saved to: bloatnet_config_max_size_24kb.txt
97+
✅ Successfully deployed 53100 contracts
98+
NUM_DEPLOYED_CONTRACTS = 53100
10899
```
109100

110-
This file contains all the values needed to update your test configuration.
111-
112101
### 3. Update Test Configuration
113102

114-
Edit `tests/benchmark/bloatnet/test_bloatnet.py` and update:
103+
Edit `tests/benchmark/bloatnet/test_bloatnet.py` and update with values from deployment:
115104

116105
```python
117-
FACTORY_ADDRESS = Address("0x...") # From deployment output
118-
INIT_CODE_HASH = bytes.fromhex("...") # From deployment output
119-
NUM_DEPLOYED_CONTRACTS = 55403 # Actual deployed count
106+
FACTORY_ADDRESS = Address("0x...") # From step 1 output
107+
INIT_CODE_HASH = bytes.fromhex("...") # From step 1 output
108+
NUM_DEPLOYED_CONTRACTS = 53100 # From step 2 output
120109
```
121110

122-
### 5. Run Benchmark Tests
111+
### 4. Run Benchmark Tests
123112

113+
#### Generate Test Fixtures
124114
```bash
125115
# Run with specific gas values (in millions)
126116
uv run fill --fork=Prague --gas-benchmark-values=150 \
127117
tests/benchmark/bloatnet/test_bloatnet.py --clean
128118

129-
# With EVM traces for analysis
119+
# Multiple gas values
120+
uv run fill --fork=Prague --gas-benchmark-values=1,5,50,150 \
121+
tests/benchmark/bloatnet/test_bloatnet.py
122+
```
123+
124+
#### Execute Against Live Client
125+
```bash
126+
# Start a test node (e.g., Geth)
127+
geth --dev --http --http.api eth,web3,net,debug
128+
129+
# Run tests
130+
uv run execute remote --rpc-endpoint http://127.0.0.1:8545 \
131+
--rpc-chain-id 1337 --rpc-seed-key 0x0000000000000000000000000000000000000000000000000000000000000001 \
132+
tests/benchmark/bloatnet/test_bloatnet.py \
133+
--fork=Prague --gas-benchmark-values=150 -v
134+
```
135+
136+
#### With EVM Traces for Analysis
137+
```bash
130138
uv run fill --fork=Prague --gas-benchmark-values=150 \
131139
--evm-dump-dir=traces/ --traces \
132140
tests/benchmark/bloatnet/test_bloatnet.py
133141

134-
# Multiple gas values
135-
uv run fill --fork=Prague --gas-benchmark-values=5,50,150 \
136-
tests/benchmark/bloatnet/test_bloatnet.py
142+
# Analyze opcodes executed
143+
jq -r '.opName' traces/**/*.jsonl | sort | uniq -c
137144
```

0 commit comments

Comments
 (0)