Dynamic Gas Pricing
Adaptive gas pricing and limits that respond to network congestion
LP-3650: Dynamic Gas Pricing
Status: Final Type: Standards Track Category: Core Created: 2025-01-15
Status note (2026-05-18): LP-3650 is Lux-native. The dynamic-fee formulae draw on public prior art (Ethereum EIP-1559 base-fee mechanism extended with exponential demand tracking). LP-3650 is live on Lux from genesis — no per-upgrade timestamp gate.
Abstract
This Lux Proposal introduces adaptive gas pricing and limits that respond to network congestion, improving user experience and network stability on the Lux C-Chain. The mechanism is Lux-native and is live from genesis.
Motivation
Static gas limits and pricing mechanisms struggle to handle varying network loads. LP-176 introduces dynamic adjustments that:
- Prevent Spam: Higher prices during congestion deter spam attacks
- Improve UX: Predictable costs during normal operation
- Optimize Throughput: Dynamic limits maximize block space utilization
- Maintain Stability: Smooth price transitions prevent shock
Specification
Gas Price Discovery
Base fee adjusts exponentially based on block fullness:
newBaseFee = currentBaseFee * (1 + (gasUsed - target) / (target * denominator))
Parameters:
MinBaseFee: 25 gwei (minimum base fee)MaxBaseFee: 1000 gwei (maximum base fee)BaseFeeChangeDenominator: 8 (controls adjustment speed)ElasticityMultiplier: 2 (target vs max ratio)
Dynamic Gas Limits
Block gas limit adjusts based on sustained demand:
targetGasPerSecond = baseTarget * e^(excessTarget / conversionRate)
maxGasPerBlock = targetGasPerSecond * ElasticityMultiplier
Parameters:
MinTargetPerSecond: 1,000,000 gas/secMaxTargetChangeRate: 1024 (max adjustment per block)TargetToMax: 2 (max is 2x target)TimeToFillCapacity: 5 seconds
Price Doubling Behavior
Under sustained load, prices double approximately every 60 seconds:
time_to_double = ln(2) * conversionRate / demand_rate
Rationale
Design Decisions
1. Exponential Adjustment: Linear adjustments don't respond quickly enough to sudden demand changes. Exponential scaling provides rapid response to congestion while maintaining stability during normal operation.
2. Minimum Base Fee: A floor of 25 gwei prevents zero-cost spam while remaining affordable for normal users. This balances accessibility with attack resistance.
3. Elasticity Multiplier of 2x: Allowing blocks up to 2x target provides burst capacity for legitimate demand spikes while keeping long-term averages at target.
4. 60-Second Price Doubling: This rate is aggressive enough to deter sustained attacks but slow enough to give users time to react and adjust their gas prices.
Alternatives Considered
- Fixed EIP-1559: Rejected due to inability to adapt to Lux's multi-chain architecture
- Linear Scaling: Rejected as too slow to respond to attacks
- Auction-Based: Rejected due to complexity and poor UX
- Time-Weighted Average: Rejected as it allows manipulation through timing
Tooling Compatibility
LP-3650 parameter shapes are exposed via standard EVM RPC
(eth_baseFee, eth_feeHistory) so cross-chain gas-estimation tooling
and wallets function without Lux-specific adapters.
Implementation
Location
Primary Implementation: node/vms/evm/lp176/
Key files:
lp176.go- Core math and state trackinglp176_test.go- Unit tests and verification
Plugin Interface: geth/plugin/evm/upgrade/lp176/
Files:
params.go- Configuration parameters
Integration Points
-
Block Building (
miner/worker.go):- Calculates dynamic gas limit before building block
- Updates target excess after each block
-
Fee Calculation (
core/state_processor.go):- Applies base fee to transactions
- Validates fee sufficiency
-
Configuration (
params/config.go):- Network-specific activation timestamps
- Parameter overrides for testing
Activation
LP-176 activates via network upgrade at a specified timestamp:
type ChainConfig struct {
// ... existing fields
LP176Timestamp *uint64 `json:"lp176Timestamp,omitempty"`
}
Test Cases
Unit Tests
Coverage: 100% of core logic
Test cases:
- Target calculation under various loads
- Excess adjustment boundary conditions
- Price doubling verification
- Min/max constraint enforcement
// Test: Base fee adjustment
func TestBaseFeeAdjustment(t *testing.T) {
cases := []struct {
name string
currentBaseFee uint64
gasUsed uint64
gasTarget uint64
expected uint64
}{
{"below target", 100, 5000000, 10000000, 94}, // 6% decrease
{"at target", 100, 10000000, 10000000, 100}, // no change
{"above target", 100, 15000000, 10000000, 106}, // 6% increase
{"at min", 25, 0, 10000000, 25}, // stays at min
{"approaching max", 950, 20000000, 10000000, 1000}, // caps at max
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
result := calculateNewBaseFee(tc.currentBaseFee, tc.gasUsed, tc.gasTarget)
require.Equal(t, tc.expected, result)
})
}
}
// Test: Dynamic gas limit
func TestDynamicGasLimit(t *testing.T) {
config := &LP176Config{
MinTargetPerSecond: 1_000_000,
MaxTargetChangeRate: 1024,
TargetToMax: 2,
TimeToFillCapacity: 5,
}
// Normal conditions
target, max := calculateGasLimits(config, 0)
require.Equal(t, uint64(5_000_000), target)
require.Equal(t, uint64(10_000_000), max)
// Sustained load (high excess)
target, max = calculateGasLimits(config, 1_000_000)
require.Greater(t, target, uint64(5_000_000))
require.Equal(t, target*2, max)
}
// Test: Price doubling time
func TestPriceDoublingTime(t *testing.T) {
// Under sustained 100% load, price should double in ~60 seconds
startPrice := uint64(100)
price := startPrice
blocks := 0
for price < startPrice*2 {
price = calculateNewBaseFee(price, 20_000_000, 10_000_000)
blocks++
}
// At 2-second blocks, 60 seconds = 30 blocks
require.InDelta(t, 30, blocks, 5)
}
Integration Tests
Location: tests/e2e/c/dynamic_fees.go
Scenarios:
- Normal load (stable prices)
- Sustained congestion (price escalation)
- Spike recovery (smooth de-escalation)
- Edge cases (min/max boundaries)
Performance Benchmarks
Results:
- Target calculation: < 1μs
- State update: < 100ns
- Zero allocation overhead
Backwards Compatibility
LP-176 is a consensus-breaking change requiring coordinated network upgrade. Pre-LP-176 blocks use static gas limits and EIP-1559 base fee.
Migration: Smooth transition at activation timestamp with no state migration required.
Security Considerations
Attack Vectors
- Sustained Load Attack: Mitigated by exponential price growth
- Oscillation Attack: Prevented by smooth adjustment curves
- State Bloat: Dynamic limits prevent excessive state growth
Audits
- Internal security review: 2025-01-10
- External audit: Pending
References
Copyright
Copyright (C) 2025 Lux Partners Limited. All rights reserved.