Skip to content

fix: disable post-Jovian DA footprint cap in benchmark#191

Open
meyer9 wants to merge 1 commit into
mainfrom
meyer9/disable-da-footprint-cap-in-benchmark
Open

fix: disable post-Jovian DA footprint cap in benchmark#191
meyer9 wants to merge 1 commit into
mainfrom
meyer9/disable-da-footprint-cap-in-benchmark

Conversation

@meyer9
Copy link
Copy Markdown
Collaborator

@meyer9 meyer9 commented May 29, 2026

Problem

In the mainnet config benchmark (Scale Base over 150M gas limit), the mainnet-transfer-only and mainnet-account-create-full-block payloads plateau at exactly 52.6% of the configured gas limit regardless of node capacity:

Payload 250M limit gas/per_block Fill Per-flashblock headroom
storage-create-full-block 245 M 98% 0.9–1.9%
mainnet-transfer-only 131 M 52.6% 47.4% (every block)
mainnet-account-create-full-block 131 M 52.6% 47.4% (every block)

(Run test-1779411190779930; the 47.4% headroom is identical across all 900 blocks and across all 150M/200M/250M gas limits, with a range of 0.10–0.36%.)

Root cause

The Jovian DA-footprint cap in base/crates/builder/core/src/execution.rs::is_tx_over_limits was firing before the gas cap:

let tx_da_footprint = total_da_bytes_used.saturating_mul(da_footprint_gas_scalar as u64);
if tx_da_footprint > limits.block_da_footprint_limit.unwrap_or(limits.block_gas_limit) {
    return Err(TxnExecutionError::DAFootprintLimitExceeded { .. });
}

The benchmark hardcoded DAFootprintGasScalar: 400, and block_da_footprint_limit defaults to block_gas_limit. Effective rule:

cumulative_da_bytes × 400 ≤ block_gas_limit
→ max DA bytes/block = block_gas_limit / 400

For ~100 B-per-tx transferonly:

Gas limit Predicted tx/block (= limit / 400 / 100) Observed tx/block
150 M 3,750 3,751
200 M 5,000 5,000
250 M 6,250 6,251

Variance < 0.03% across three limits — conclusive.

storage-create-full-block was unaffected because its txs are heavy in gas (~2.27 M) but light in DA (~200 B), so the gas cap fires first.

Fix

Set DAFootprintGasScalar to 0 in generatePayloadAttributes. The check then computes tx_da_footprint = bytes × 0 = 0 ≤ limit and always passes. The scalar is serialized into the L1 attributes deposit tx and written to L2 state; the builder reads it via fetch_da_footprint_gas_scalar per block. Setup blocks (which run with GasLimitSetup = 1e9) propagate the new scalar before benchmark blocks start.

Expected outcome on next rerun

  • mainnet-transfer-only @ 250M: 131 M → ~245+ M gas/per_block
  • mainnet-account-create-full-block @ 250M: was bound by both DA cap and EL speed (989 ms get_payload); will now be a true EL-limited measurement
  • storage-create-full-block @ 250M: unchanged (~245 M, already gas-capped)
  • base-mainnet-simulation @ 250M: still won't fill (separate worker-side scaleFactor bug, not addressed here)

Verification

  • go build ./runner/... clean
  • go vet ./runner/network/consensus/... clean
  • No tests in the consensus package exercise this code path
  • Mechanism source-verified against base/crates/builder/core/src/execution.rs

Rationale

The benchmark's question is "how much L2 gas/sec can the EL execute?". L1 DA capacity is a separate concern measured elsewhere; baking it into the gas-throughput benchmark masks the EL-throughput signal for cheap-tx workloads.

Draft because end-to-end validation requires a single ~12 h mainnet rerun.

The hardcoded DAFootprintGasScalar=400 caused the builder's per-block DA
footprint cap (base/crates/builder/core/src/execution.rs::is_tx_over_limits)
to fire before the gas cap on cheap-tx workloads. Effective rule:

  cumulative_da_bytes * 400 <= block_gas_limit
  => max DA bytes/block = block_gas_limit / 400

With transferonly txs averaging ~100 bytes DA, the predicted vs observed
tx counts match to within 0.03% across three gas limits in run
test-1779411190779930:

  150M limit: 3750 predicted / 3751 observed
  200M limit: 5000 predicted / 5000 observed
  250M limit: 6250 predicted / 6251 observed

This capped gas/per_block at exactly 52.6% of the configured gas limit
for transfer-only and account-create-full-block workloads, regardless of
EL capacity. storage-create-full-block was unaffected (heavy gas/tx,
light DA/tx) and correctly filled to ~98%.

Setting the scalar to 0 makes the check
'tx_da_footprint = cumulative_da_bytes * 0 = 0 <= limit' always pass,
restoring the gas limit as the sole per-block cap. The scalar is
serialized into the L1 attributes deposit tx and written to L2 state at
0x4200...0015; the builder reads it via fetch_da_footprint_gas_scalar
per block. Setup blocks propagate the new value before benchmark blocks
start, so the first real benchmark block already sees scalar=0.

The benchmark's purpose is measuring EL gas throughput; L1 DA capacity
is a separate concern that should not artificially cap these tests.
@cb-heimdall
Copy link
Copy Markdown
Collaborator

🟡 Heimdall Review Status

Requirement Status More Info
Reviews 🟡 0/1
Denominator calculation
Show calculation
1 if user is bot 0
1 if user is external 0
2 if repo is sensitive 0
From .codeflow.yml 1
Additional review requirements
Show calculation
Max 0
0
From CODEOWNERS 0
Global minimum 0
Max 1
1
1 if commit is unverified 0
Sum 1

@meyer9 meyer9 marked this pull request as ready for review May 29, 2026 20:07
@meyer9 meyer9 requested a review from wlawt May 29, 2026 20:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants