Skip to content

CalcBaseFee can divide by zero when elasticity == 0 (invalid extraData) #757

Description

@byteflyfunny

Summary
CalcBaseFee can panic with division-by-zero when elasticity == 0 is decoded from Optimism extraData.

Steps to reproduce

  1. Construct a block header in the Arsia era with extraData that decodes to elasticity == 0.
  2. Trigger base fee calculation (e.g., during header verification or block import).
  3. 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 := &params.ChainConfig{
ChainID: big.NewInt(1),
LondonBlock: big.NewInt(0),
Optimism: &params.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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions