Summary
CalcBaseFee can panic with division-by-zero when elasticity == 0 is decoded from Optimism extraData.
Steps to reproduce
- Construct a block header in the Arsia era with extraData that decodes to elasticity == 0.
- Trigger base fee calculation (e.g., during header verification or block import).
- Observe a panic at parent.GasLimit / elasticity.
Expected behavior
Invalid extraData should be rejected cleanly, or CalcBaseFee should handle elasticity == 0 without panicking.
Actual behavior
CalcBaseFee performs parent.GasLimit / elasticity without guarding against elasticity == 0, causing a panic.
Relevant code
consensus/misc/eip1559/eip1559.go
parentGasTarget := parent.GasLimit / elasticity
parentGasMetered := parent.GasUsed
Notes / Additional context
- ExtraData validation currently allows elasticity == 0 (it only forbids denominator == 0 when elasticity != 0).
- DecodeOptimismExtraData returns 0,0,nil on invalid formats.
- ExtraData validation is currently tied to Engine API validation; malformed headers may still reach CalcBaseFee through other paths.
- Impact: a malformed header can crash the node (DoS).
Suggested fix
- Reject elasticity == 0 during extraData validation (e.g., in ValidateHolocene1559Params / ValidateOptimismExtraData).
- Add a defensive check in CalcBaseFee to return an error or safe fallback when elasticity == 0.
- Ensure extraData validation is enforced in the consensus/header validation path, not only in Engine API handling.
Minimal PoC (Go)
package main
import (
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/consensus/misc/eip1559"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params"
)
func main() {
// Chain config with Arsia activated at time=0
cfg := ¶ms.ChainConfig{
ChainID: big.NewInt(1),
LondonBlock: big.NewInt(0),
Optimism: ¶ms.OptimismConfig{},
}
// Make Arsia active at time 0
t0 := uint64(0)
cfg.EcotoneTime = &t0 // or the appropriate Arsia time field in your config
parent := &types.Header{
Number: big.NewInt(1),
GasLimit: 30_000_000,
GasUsed: 0,
BaseFee: big.NewInt(1),
Time: 1, // > Arsia activation time
Extra: []byte{0x01}, // invalid/short extraData -> DecodeOptimismExtraData returns 0,0,nil
}
fmt.Println("About to call CalcBaseFee; expect panic if elasticity==0")
_ = eip1559.CalcBaseFee(cfg, parent)
}
Example log output
panic: runtime error: integer divide by zero
goroutine 1 [running]:
github.com/ethereum/go-ethereum/consensus/misc/eip1559.CalcBaseFee(...)
.../consensus/misc/eip1559/eip1559.go:80
main.main(...)
.../poc.go:32
Summary
CalcBaseFee can panic with division-by-zero when elasticity == 0 is decoded from Optimism extraData.
Steps to reproduce
Expected behavior
Invalid extraData should be rejected cleanly, or CalcBaseFee should handle elasticity == 0 without panicking.
Actual behavior
CalcBaseFee performs parent.GasLimit / elasticity without guarding against elasticity == 0, causing a panic.
Relevant code
consensus/misc/eip1559/eip1559.go
parentGasTarget := parent.GasLimit / elasticity
parentGasMetered := parent.GasUsed
Notes / Additional context
Suggested fix
Minimal PoC (Go)
package main
import (
"fmt"
"math/big"
)
func main() {
// Chain config with Arsia activated at time=0
cfg := ¶ms.ChainConfig{
ChainID: big.NewInt(1),
LondonBlock: big.NewInt(0),
Optimism: ¶ms.OptimismConfig{},
}
// Make Arsia active at time 0
t0 := uint64(0)
cfg.EcotoneTime = &t0 // or the appropriate Arsia time field in your config
}
Example log output
panic: runtime error: integer divide by zero
goroutine 1 [running]:
github.com/ethereum/go-ethereum/consensus/misc/eip1559.CalcBaseFee(...)
.../consensus/misc/eip1559/eip1559.go:80
main.main(...)
.../poc.go:32