Skip to content

Commit d0753cb

Browse files
authored
feat: fancier gas-benchmarks (#13899)
Fixes #13076 Alters the gas_benchmark so the output looks like this instead: ```md Function | Metric | No Validators (gas/tx) | 100 Validators (gas/tx) | Δ Gas (gas/tx) | % Overhead -------------------------+---------+------------------------+-------------------------+------------------------+----------------- forward | Min | 280145 (778.18) | 614490 (1706.92) | 334345 (928.74) | 119.35% forward | Avg | 288582 (801.62) | 679903 (1888.62) | 391321 (1087.00) | 135.60% forward | Median | 285127 (792.02) | 619574 (1721.04) | 334447 (929.02) | 117.30% forward | Max | 349164 (969.90) | 2104890 (5846.92) | 1755726 (4877.02) | 502.84% forward | # Calls | 100 | 100 | 0 | 0.00% -------------------------+---------+------------------------+-------------------------+------------------------+----------------- submitEpochRootProof | Min | 858815 (74.55) | 858815 (74.55) | 0 (0.00) | 0.00% submitEpochRootProof | Avg | 876459 (76.08) | 870759 (75.59) | -5700 (-0.49) | -0.65% submitEpochRootProof | Median | 858827 (74.55) | 858827 (74.55) | 0 (0.00) | 0.00% submitEpochRootProof | Max | 911736 (79.14) | 894636 (77.66) | -17100 (-1.48) | -1.88% submitEpochRootProof | # Calls | 3 | 3 | 0 | 0.00% -------------------------+---------+------------------------+-------------------------+------------------------+----------------- ```
1 parent 9f14521 commit d0753cb

File tree

3 files changed

+168
-83
lines changed

3 files changed

+168
-83
lines changed

l1-contracts/bootstrap.sh

Lines changed: 121 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -135,15 +135,9 @@ function gas_report {
135135
function gas_benchmark {
136136
check=${1:-"no"}
137137
echo_header "Benchmarking gas"
138-
forge --version
139138

140-
FORGE_GAS_REPORT=true forge test \
141-
--match-contract "BenchmarkRollupTest" \
142-
--fuzz-seed 42 \
143-
--isolate \
144-
> gas_benchmark.new.tmp
145-
grep "^|" gas_benchmark.new.tmp > gas_benchmark.new.md
146-
rm gas_benchmark.new.tmp
139+
validator_costs
140+
147141
diff gas_benchmark.new.md gas_benchmark.md > gas_benchmark.diff || true
148142

149143
if [ -s gas_benchmark.diff -a "$check" = "check" ]; then
@@ -154,6 +148,125 @@ function gas_benchmark {
154148
mv gas_benchmark.new.md gas_benchmark.md
155149
}
156150

151+
function validator_costs {
152+
echo_header "Comparing gas costs with and without validators"
153+
forge --version
154+
155+
# Run test without validators
156+
echo "Running test without validators..."
157+
FORGE_GAS_REPORT=true forge test \
158+
--match-contract "BenchmarkRollupTest" \
159+
--match-test "test_no_validators" \
160+
--fuzz-seed 42 \
161+
--isolate \
162+
> no_validators.tmp
163+
164+
# Run test with 100 validators
165+
echo "Running test with 100 validators..."
166+
FORGE_GAS_REPORT=true forge test \
167+
--match-contract "BenchmarkRollupTest" \
168+
--match-test "test_100_validators" \
169+
--fuzz-seed 42 \
170+
--isolate \
171+
> with_validators.tmp
172+
173+
file_no="no_validators.tmp" # without validators
174+
file_yes="with_validators.tmp" # with validators
175+
report="gas_benchmark.new.md" # will be overwritten each run
176+
177+
# keep ONLY these functions, in this order
178+
wanted_funcs="forward submitEpochRootProof"
179+
180+
# one label per numeric column (use | to separate)
181+
labels='Min|Avg|Median|Max|# Calls'
182+
183+
awk -v keep="$wanted_funcs" -v lbl="$labels" \
184+
-v f_no="$file_no" -v f_yes="$file_yes" '
185+
function trim(s){gsub(/^[[:space:]]+|[[:space:]]+$/,"",s); return s}
186+
# cell(raw [, scaled])
187+
# If you call it with ONE argument, you get the raw value only.
188+
# If you call it with TWO arguments, you get "raw (scaled)" padded to 22.
189+
function cell(raw, scaled, s) {
190+
# Was a second parameter supplied?
191+
if ( scaled == "" ) # argument omitted → print raw only
192+
return sprintf("%22d", raw)
193+
194+
s = sprintf("%10d (%.2f)", raw, scaled)
195+
return sprintf("%-22s", s) # left-pad / truncate to 22 chars
196+
}
197+
198+
BEGIN{
199+
# ---------------- wanted functions & labels (unchanged) ---------------
200+
nf = split(keep, F, /[[:space:]]+/)
201+
for (i = 1; i <= nf; i++) { order[i] = F[i]; want[F[i]] }
202+
split(lbl, L, /\|/); nLab = length(L)
203+
204+
# ---------------- fixed-width formats ---------------------------------
205+
# header row
206+
hdr = "%-24s | %-7s | %22s | %23s | %22s | %12s\n"
207+
sep = "-------------------------+---------+------------------------+-------------------------+------------------------+-----------------"
208+
# data row (the three %22s will already be fully padded strings)
209+
row = "%-24s | %-7s | %22s | %23s | %22s | %10.2f%%\n"
210+
211+
printf hdr, "Function", "Metric",
212+
"No Validators (gas/tx)", "100 Validators (gas/tx)", "Δ Gas (gas/tx)", "% Overhead"
213+
print sep
214+
215+
FS="|"; OFS=""
216+
}
217+
# ---------- first file: without validators ----------------------------------
218+
FNR==NR {
219+
if($0 !~ /^\|/) next
220+
split($0, C) # C[1] "", C[2] fn, C[3..] numbers
221+
fn = trim(C[2])
222+
if(!(fn in want)) next
223+
for(i=3; i<=NF-1; i++) base[fn,i] = trim(C[i]) + 0
224+
cols[fn] = NF - 3 # remember how many numeric cols
225+
next
226+
}
227+
# ---------- second file: with validators ------------------------------------
228+
{
229+
if($0 !~ /^\|/) next
230+
split($0, C)
231+
fn = trim(C[2])
232+
if(!(fn in want)) next
233+
for(i=3; i<=NF-1; i++) with[fn,i] = trim(C[i]) + 0
234+
cols[fn] = NF - 3
235+
}
236+
# ---------- emit table -------------------------------------------------------
237+
END{
238+
for (k = 1; k <= nf; k++) {
239+
fn = order[k]
240+
div = (fn == "forward" ? 360 : 11520) # change 11520→720 if desired
241+
242+
for (j = 1; j <= cols[fn]; j++) {
243+
idx = j + 2
244+
metric = L[j]
245+
a = base[fn,idx] + 0
246+
b = with[fn,idx] + 0
247+
diff = b - a
248+
pct = (a ? diff * 100.0 / a : 0)
249+
250+
if (metric == "# Calls") {
251+
c1 = cell(a)
252+
c2 = cell(b)
253+
c3 = cell(diff)
254+
} else {
255+
c1 = cell(a, a/div)
256+
c2 = cell(b, b/div)
257+
c3 = cell(diff,diff/div)
258+
}
259+
printf row, fn, metric, c1, c2, c3, pct
260+
}
261+
print sep
262+
}
263+
}
264+
' "$file_no" "$file_yes" > "$report"
265+
266+
# Clean up temporary files
267+
rm no_validators.tmp with_validators.tmp
268+
}
269+
157270
# First argument is a branch name (e.g. master, or the latest version e.g. 1.2.3) to push to the head of.
158271
# Second argument is the tag name (e.g. v1.2.3, or commit-<hash>).
159272
# Third argument is the semver for package.json (e.g. 1.2.3 or 1.2.3-commit.<hash>)

l1-contracts/gas_benchmark.md

Lines changed: 14 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,14 @@
1-
| src/core/Rollup.sol:Rollup Contract | | | | | |
2-
| Deployment Cost | Deployment Size | | | | |
3-
|-------------------------------------+-----------------+----------+----------+----------+---------|
4-
| 8471673 | 42045 | | | | |
5-
|-------------------------------------+-----------------+----------+----------+----------+---------|
6-
| | | | | | |
7-
|-------------------------------------+-----------------+----------+----------+----------+---------|
8-
| Function Name | Min | Avg | Median | Max | # Calls |
9-
|-------------------------------------+-----------------+----------+----------+----------+---------|
10-
| cheat__InitialiseValidatorSet | 14839438 | 14839438 | 14839438 | 14839438 | 1 |
11-
|-------------------------------------+-----------------+----------+----------+----------+---------|
12-
| getBlock | 9230 | 9230 | 9230 | 9230 | 6 |
13-
|-------------------------------------+-----------------+----------+----------+----------+---------|
14-
| getBurnAddress | 369 | 369 | 369 | 369 | 1 |
15-
|-------------------------------------+-----------------+----------+----------+----------+---------|
16-
| getCurrentEpoch | 2957 | 2957 | 2957 | 2957 | 490 |
17-
|-------------------------------------+-----------------+----------+----------+----------+---------|
18-
| getCurrentProposer | 136098 | 149301 | 136098 | 466200 | 200 |
19-
|-------------------------------------+-----------------+----------+----------+----------+---------|
20-
| getCurrentSlot | 2713 | 2713 | 2713 | 2713 | 490 |
21-
|-------------------------------------+-----------------+----------+----------+----------+---------|
22-
| getEpochCommittee | 135758 | 149031 | 135758 | 467617 | 100 |
23-
|-------------------------------------+-----------------+----------+----------+----------+---------|
24-
| getEpochForBlock | 7043 | 7043 | 7043 | 7043 | 196 |
25-
|-------------------------------------+-----------------+----------+----------+----------+---------|
26-
| getFeeAssetPortal | 2497 | 2497 | 2497 | 2497 | 1 |
27-
|-------------------------------------+-----------------+----------+----------+----------+---------|
28-
| getFeeHeader | 3435 | 3435 | 3435 | 3435 | 95 |
29-
|-------------------------------------+-----------------+----------+----------+----------+---------|
30-
| getManaBaseFeeAt | 30748 | 44008 | 44436 | 44883 | 195 |
31-
|-------------------------------------+-----------------+----------+----------+----------+---------|
32-
| getPendingBlockNumber | 2485 | 2485 | 2485 | 2485 | 394 |
33-
|-------------------------------------+-----------------+----------+----------+----------+---------|
34-
| getProvenBlockNumber | 2468 | 2468 | 2468 | 2468 | 3 |
35-
|-------------------------------------+-----------------+----------+----------+----------+---------|
36-
| getTimestampForSlot | 2780 | 2780 | 2780 | 2780 | 195 |
37-
|-------------------------------------+-----------------+----------+----------+----------+---------|
38-
| setProvingCostPerMana | 25893 | 25920 | 25893 | 28693 | 101 |
39-
|-------------------------------------+-----------------+----------+----------+----------+---------|
40-
| submitEpochRootProof | 858815 | 870759 | 858827 | 894636 | 3 |
41-
| src/core/messagebridge/Inbox.sol:Inbox Contract | | | | | |
42-
| Deployment Cost | Deployment Size | | | | |
43-
|-------------------------------------------------+-----------------+-----+--------+-----+---------|
44-
| 0 | 6627 | | | | |
45-
|-------------------------------------------------+-----------------+-----+--------+-----+---------|
46-
| | | | | | |
47-
|-------------------------------------------------+-----------------+-----+--------+-----+---------|
48-
| Function Name | Min | Avg | Median | Max | # Calls |
49-
|-------------------------------------------------+-----------------+-----+--------+-----+---------|
50-
| getFeeAssetPortal | 234 | 234 | 234 | 234 | 1 |
51-
| src/periphery/Forwarder.sol:Forwarder Contract | | | | | |
52-
| Deployment Cost | Deployment Size | | | | |
53-
|------------------------------------------------+-----------------+--------+--------+---------+---------|
54-
| 358690 | 1553 | | | | |
55-
|------------------------------------------------+-----------------+--------+--------+---------+---------|
56-
| | | | | | |
57-
|------------------------------------------------+-----------------+--------+--------+---------+---------|
58-
| Function Name | Min | Avg | Median | Max | # Calls |
59-
|------------------------------------------------+-----------------+--------+--------+---------+---------|
60-
| forward | 614550 | 679900 | 619544 | 2104830 | 100 |
1+
Function | Metric | No Validators (gas/tx) | 100 Validators (gas/tx) | Δ Gas (gas/tx) | % Overhead
2+
-------------------------+---------+------------------------+-------------------------+------------------------+-----------------
3+
forward | Min | 280145 (778.18) | 614490 (1706.92) | 334345 (928.74) | 119.35%
4+
forward | Avg | 288582 (801.62) | 679903 (1888.62) | 391321 (1087.00) | 135.60%
5+
forward | Median | 285127 (792.02) | 619574 (1721.04) | 334447 (929.02) | 117.30%
6+
forward | Max | 349164 (969.90) | 2104890 (5846.92) | 1755726 (4877.02) | 502.84%
7+
forward | # Calls | 100 | 100 | 0 | 0.00%
8+
-------------------------+---------+------------------------+-------------------------+------------------------+-----------------
9+
submitEpochRootProof | Min | 858815 (74.55) | 858815 (74.55) | 0 (0.00) | 0.00%
10+
submitEpochRootProof | Avg | 876459 (76.08) | 870759 (75.59) | -5700 (-0.49) | -0.65%
11+
submitEpochRootProof | Median | 858827 (74.55) | 858827 (74.55) | 0 (0.00) | 0.00%
12+
submitEpochRootProof | Max | 911736 (79.14) | 894636 (77.66) | -17100 (-1.48) | -1.88%
13+
submitEpochRootProof | # Calls | 3 | 3 | 0 | 0.00%
14+
-------------------------+---------+------------------------+-------------------------+------------------------+-----------------

l1-contracts/test/benchmark/happy.t.sol

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,7 @@ import {Forwarder} from "@aztec/periphery/Forwarder.sol";
6464

6565
// solhint-disable comprehensive-interface
6666

67-
uint256 constant MANA_TARGET = 100000000;
68-
uint256 constant VALIDATOR_COUNT = 100;
67+
uint256 constant MANA_TARGET = 1e8;
6968

7069
contract FakeCanonical is IRewardDistributor {
7170
uint256 public constant BLOCK_REWARD = 50e18;
@@ -131,11 +130,9 @@ contract BenchmarkRollupTest is FeeModelTestPoints, DecoderBase {
131130
mapping(address attester => uint256 privateKey) internal attesterPrivateKeys;
132131
mapping(address proposer => address attester) internal proposerToAttester;
133132

134-
constructor() {
135-
FeeLib.initialize(MANA_TARGET, EthValue.wrap(100));
136-
}
133+
Forwarder internal baseForwarder = new Forwarder(address(this));
137134

138-
function setUp() public {
135+
modifier prepare(uint256 _validatorCount) {
139136
// We deploy a the rollup and sets the time and all to
140137
vm.warp(l1Metadata[0].timestamp - SLOT_DURATION);
141138

@@ -170,9 +167,9 @@ contract BenchmarkRollupTest is FeeModelTestPoints, DecoderBase {
170167
vm.label(rollup.getBurnAddress(), "BURN_ADDRESS");
171168

172169
// We are going to set up all of the validators
173-
CheatDepositArgs[] memory initialValidators = new CheatDepositArgs[](VALIDATOR_COUNT);
170+
CheatDepositArgs[] memory initialValidators = new CheatDepositArgs[](_validatorCount);
174171

175-
for (uint256 i = 1; i < VALIDATOR_COUNT + 1; i++) {
172+
for (uint256 i = 1; i < _validatorCount + 1; i++) {
176173
uint256 attesterPrivateKey = uint256(keccak256(abi.encode("attester", i)));
177174
address attester = vm.addr(attesterPrivateKey);
178175
attesterPrivateKeys[attester] = attesterPrivateKey;
@@ -189,19 +186,37 @@ contract BenchmarkRollupTest is FeeModelTestPoints, DecoderBase {
189186
});
190187
}
191188

192-
asset.mint(address(this), TestConstants.AZTEC_MINIMUM_STAKE * VALIDATOR_COUNT);
193-
asset.approve(address(rollup), TestConstants.AZTEC_MINIMUM_STAKE * VALIDATOR_COUNT);
189+
asset.mint(address(this), TestConstants.AZTEC_MINIMUM_STAKE * _validatorCount);
190+
asset.approve(address(rollup), TestConstants.AZTEC_MINIMUM_STAKE * _validatorCount);
194191
rollup.cheat__InitialiseValidatorSet(initialValidators);
195192
asset.mint(address(rollup.getFeeAssetPortal()), 1e30);
196193

197194
asset.transferOwnership(address(fakeCanonical));
195+
196+
_;
197+
}
198+
199+
constructor() {
200+
FeeLib.initialize(MANA_TARGET, EthValue.wrap(100));
198201
}
199202

200203
function _loadL1Metadata(uint256 index) internal {
201204
vm.roll(l1Metadata[index].block_number);
202205
vm.warp(l1Metadata[index].timestamp);
203206
}
204207

208+
function test_no_validators() public prepare(0) {
209+
benchmark();
210+
}
211+
212+
function test_48_validators() public prepare(48) {
213+
benchmark();
214+
}
215+
216+
function test_100_validators() public prepare(100) {
217+
benchmark();
218+
}
219+
205220
/**
206221
* @notice Constructs a fake block that is not possible to prove, but passes the L1 checks.
207222
*/
@@ -286,7 +301,7 @@ contract BenchmarkRollupTest is FeeModelTestPoints, DecoderBase {
286301
return Signature({isEmpty: false, v: v, r: r, s: s});
287302
}
288303

289-
function test_Benchmarking() public {
304+
function benchmark() public {
290305
// Do nothing for the first epoch
291306
Slot nextSlot = Slot.wrap(EPOCH_DURATION + 1);
292307
Epoch nextEpoch = Epoch.wrap(2);
@@ -323,10 +338,13 @@ contract BenchmarkRollupTest is FeeModelTestPoints, DecoderBase {
323338
bytes[] memory data = new bytes[](1);
324339
data[0] = abi.encodeCall(IRollupCore.propose, (b.proposeArgs, b.signatures, b.blobInputs));
325340

326-
address caller = proposerToAttester[proposer];
327-
vm.prank(caller);
328-
Forwarder(proposer).forward(targets, data);
329-
// rollup.propose(b.proposeArgs, b.signatures, b.blobInputs);
341+
if (proposer == address(0)) {
342+
baseForwarder.forward(targets, data);
343+
} else {
344+
address caller = proposerToAttester[proposer];
345+
vm.prank(caller);
346+
Forwarder(proposer).forward(targets, data);
347+
}
330348

331349
nextSlot = nextSlot + Slot.wrap(1);
332350
}

0 commit comments

Comments
 (0)