Zero TargetBlockUtilization
disables fee market
Description
The UpdateBaseGasPrice
computes the following:
baseGasPrice = someValue / (MaxGas \* TargetBlockUtilization)
Currently, at the time of writing, ValidateBasic
allows TargetBlockUtilization = 0
. A governance-param change to zero triggers a divide-by-zero panic every block.
The panic is caught by
defer func() {
if rec := recover(); rec != nil {
logger.Error("Panic recovered in state.UpdateBaseGasPrice", "err", rec)
s.BaseGasPrice = params.MinBaseGasPrice
gasPrice = s.BaseGasPrice
}
}()
so the chain stays alive, but BaseGasPrice
is reset to the floor each block, and an error is logged every block.
Impact
This has the following impacts.
The fee-market mechanism is effectively disabled; the gas price sticks at
MinBaseGasPrice
.Continuous error logs pollute node output and can degrade performance over time.
A griefing vector is created: one malicious param vote breaks dynamic pricing until another vote passes.
Recommendations
We recommend tightening param validation — enforce 0 < TargetBlockUtilization ≤ 1
and BaseFeeChangeDenom > 0
.
Also, add unit tests covering edge values (0, 1, negative, >1).
Remediation
This issue has been acknowledged by AtomOne, and a fix was implemented in PR #166↗.