Skip to content

feat: add --fee-strategy flag for adaptive fee calculation#209

Merged
qu0b merged 5 commits intoethpandaops:masterfrom
qu0b:fix/dynamic-fee-headroom
Mar 19, 2026
Merged

feat: add --fee-strategy flag for adaptive fee calculation#209
qu0b merged 5 commits intoethpandaops:masterfrom
qu0b:fix/dynamic-fee-headroom

Conversation

@qu0b
Copy link
Copy Markdown
Member

@qu0b qu0b commented Mar 19, 2026

Summary

  • Restores the original fee calculation as the default behavior (use provided fees or fetch from network via eth_gasPrice)
  • Moves the dynamic headroom + normal distribution fee calculation behind fee_strategy: adaptive
  • Fee strategy is per-spammer via WalletPoolConfig, not global — each spammer in daemon mode can use a different strategy
  • Keeps the client distribution fix from fix: use baseFee*2 for feeCap and distribute tx submissions across all clients #207 untouched
  • Fixes an EIP-1559 violation where feeCap < tipCap could occur in the adaptive strategy due to normal distribution sampling
  • Updates all 42 scenario call sites to use walletPool.GetSuggestedFees() (reads strategy from config)

The adaptive strategy uses a sliding window of recent block gas usage to compute dynamic headroom above the average baseFee, with a normal distribution spread across transactions. This creates a self-correcting feedback loop: when blocks are full and baseFee is rising, more transactions land below the current baseFee and get rejected, reducing throughput until baseFee recovers.

Configuration

CLI (single scenario)

spamoor eoatx --fee-strategy adaptive -h http://localhost:8545 -p <privkey>

YAML (per-spammer in spamoor run or daemon mode)

- scenario: eoatx
  name: "adaptive-spammer"
  config:
    fee_strategy: adaptive
    throughput: 50

YAML (mixed strategies — different per spammer)

- scenario: eoatx
  name: "legacy-spammer"
  config:
    throughput: 50

- scenario: eoatx
  name: "adaptive-spammer"
  config:
    fee_strategy: adaptive
    throughput: 50

Daemon mode (via UI/API)

Set fee_strategy: adaptive in the spammer config — each spammer gets its own WalletPool with independent fee strategy.

Kurtosis (spamoor_params)

spamoor_params:
  spammers:
    - scenario: eoatx
      config: {fee_strategy: adaptive, throughput: 50}

Docker

docker run ethpandaops/spamoor:latest eoatx --fee-strategy adaptive -h http://el:8545

Test plan

  • Built successfully (go build ./..., go vet ./..., go fmt ./...)
  • Tested legacy (default) strategy via CLI in Kurtosis network (geth+reth, lighthouse) — 10 tx/block confirmed
  • Tested adaptive strategy via --fee-strategy adaptive CLI flag — 10 tx/block confirmed, zero errors
  • Tested adaptive strategy via YAML config fee_strategy: adaptive in spamoor run — 10 tx/block confirmed, zero errors
  • Verified client distribution fix from fix: use baseFee*2 for feeCap and distribute tx submissions across all clients #207 is preserved

🤖 Generated with Claude Code

qu0b and others added 5 commits March 17, 2026 16:45
Replace the static baseFee*2 multiplier with adaptive fee calculation
in GetSuggestedFees (works for all scenarios, no rate manipulation):

1. Dynamic headroom (sliding window over last 10 blocks):
     50% avg fill (target) → baseFee/8  headroom (1 block of max change)
     100% avg fill         → baseFee/16 (clamped minimum)
     0% avg fill           → baseFee/4  headroom (2 blocks of max change)

2. Lagged baseFee center: uses the AVERAGE baseFee from the window
   instead of the current baseFee. When baseFee is rising, the average
   lags behind, shifting more tx below currentBaseFee → rejected by EL →
   nonce gaps → wallet stalls → reduced throughput → baseFee recovers.

3. Normal distribution spread: feeCaps sampled from N(center, sigma²)
   where sigma = headroom/1.28. ~10% canary tx sit near the floor.

4. baseFeeWei parameter (scenario default: 20 gwei) now acts as a
   MAXIMUM CAP instead of an exact override. The dynamic mechanism
   always runs — the cap only triggers if the computed feeCap exceeds
   baseFeeWei (e.g., on chains with very high baseFee). No scenario
   default changes needed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Restore original fee calculation as default (use provided fees or fetch
from network via eth_gasPrice). Move the dynamic headroom + normal
distribution fee calculation behind --fee-strategy adaptive flag.

This collapses the fee changes from PR ethpandaops#207 and the dynamic headroom
commit into a single opt-in strategy, keeping the client distribution
fix from ethpandaops#207 untouched.

Also fix EIP-1559 violation in adaptive mode where feeCap could be
lower than tipCap due to normal distribution sampling.

Configuration examples:

  # CLI (single scenario)
  spamoor eoatx --fee-strategy adaptive -h http://localhost:8545

  # CLI (yaml multi-scenario)
  spamoor run config.yaml --fee-strategy adaptive

  # Daemon
  spamoor-daemon --fee-strategy adaptive -h http://localhost:8545

  # Kurtosis (spamoor_params)
  spamoor_params:
    extra_args:
      - --fee-strategy=adaptive

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move FeeStrategy from TxPoolOptions (global) to WalletPoolConfig
(per-spammer) so each spammer in daemon mode can use a different fee
calculation strategy.

- Add FeeStrategy field to WalletPoolConfig (yaml: fee_strategy)
- Add WalletPool.GetSuggestedFees() convenience method that reads
  the strategy from its own config
- Change TxPool.GetSuggestedFees() to accept variadic feeStrategy
  parameter (backward compatible - existing callers unchanged)
- Update all 42 scenario call sites to use walletPool.GetSuggestedFees()
- Keep --fee-strategy CLI flag on single-scenario mode (cmd/spamoor)
- Remove --fee-strategy from daemon and run commands (comes from
  per-spammer YAML config instead)

Configuration examples:

  # CLI (single scenario)
  spamoor eoatx --fee-strategy adaptive -h http://localhost:8545

  # YAML (per-spammer in run or daemon mode)
  - scenario: eoatx
    config:
      fee_strategy: adaptive
      throughput: 50

  # Kurtosis (spamoor_params)
  spamoor_params:
    spammers:
      - scenario: eoatx
        config: {fee_strategy: adaptive, throughput: 50}

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Return a clear error instead of panicking if client is nil when the
adaptive strategy needs to fetch fees from the network.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add commented-out fee_strategy hint to the default YAML config shown
when creating a new spammer in the web UI.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@qu0b qu0b merged commit 1eb252b into ethpandaops:master Mar 19, 2026
6 checks passed
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