Skip to content

fix(simulator): remove double-application of scaleFactor in targetCalls#184

Merged
meyer9 merged 1 commit into
mainfrom
fix/simulator-scale-factor-double-apply-v2
May 15, 2026
Merged

fix(simulator): remove double-application of scaleFactor in targetCalls#184
meyer9 merged 1 commit into
mainfrom
fix/simulator-scale-factor-double-apply-v2

Conversation

@meyer9
Copy link
Copy Markdown
Collaborator

@meyer9 meyer9 commented May 15, 2026

Root cause

scaleFactor is applied per-tx inside sendTxs to scale up the operations each transaction performs:

// line 608 — scaleFactor applied inside each tx's operation count
expected := t.payloadParams.Mul(float64(t.numCalls+1) * t.scaleFactor)
blockCounts := expected.Sub(actual).Round()

So each tx already does scaleFactor × payloadParams operations. With avg_gas_used=35M and GasLimit=200M, scaleFactor≈5.71, so each tx does ~280 storage reads instead of the base 49.

targetCalls was then computed as:

targetCalls := uint64(math.Ceil(float64(t.numCallsPerBlock) * t.scaleFactor))
// = ceil(100 * 5.71) = 572

This multiplied scaleFactor in a second time at the tx-count level. The builder only absorbs ~100 txs/block (one numCallsPerBlock's worth of gas). After 2 blocks pendingTxs grew past 572 and callsToSend=0 forever — producing empty (deposit-only) blocks for the rest of the run.

Only affected workloads with both avg_gas_used and a numeric calls_per_block set, which is only base-mainnet-simulation in the public configs. All other payloads leave scaleFactor=1.0 so the double-application is a no-op.

Observed: 7,000+ consecutive empty blocks in a 900-block base-mainnet-simulation run.

Fix

// Before
targetCalls := uint64(math.Ceil(float64(t.numCallsPerBlock) * t.scaleFactor))

// After
targetCalls := t.numCallsPerBlock

scaleFactor belongs only in the per-tx operation calculation (line 608). numCallsPerBlock is already the correct tx count — it is derived from gas estimation that already accounts for each tx doing scaleFactor worth of operations.

scaleFactor is applied per-tx inside sendTxs at line 608:
  expected = payloadParams.Mul(numCalls+1 * scaleFactor)
meaning each tx already does scaleFactor times the base operations.

targetCalls was then computed as:
  numCallsPerBlock * scaleFactor
which multiplied scaleFactor in again — resulting in 5.71x more txs being
targeted than actually needed (e.g. 572 instead of 100 for base-mainnet-simulation
with GasLimit=200M, avg_gas_used=35M).

Since the builder only absorbs ~100 txs/block worth of those scaled ops,
pendingTxs accumulated beyond targetCalls after 2 blocks, causing callsToSend=0
forever and 7,000+ consecutive empty (deposit-only) blocks in a 900-block run.

Fix: targetCalls = numCallsPerBlock (the tx count, not the ops count).
scaleFactor belongs only in the per-tx operation calculation.
@cb-heimdall
Copy link
Copy Markdown
Collaborator

cb-heimdall commented May 15, 2026

✅ Heimdall Review Status

Requirement Status More Info
Reviews 1/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 requested a review from wlawt May 15, 2026 18:25
@meyer9 meyer9 merged commit cf47296 into main May 15, 2026
14 checks passed
@meyer9 meyer9 deleted the fix/simulator-scale-factor-double-apply-v2 branch May 15, 2026 18:55
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.

3 participants