Skip to content

Commit

Permalink
Handle Holocene EIP 1559 Params
Browse files Browse the repository at this point in the history
  • Loading branch information
mininny committed Oct 14, 2024
1 parent 38558d5 commit 77950b7
Show file tree
Hide file tree
Showing 8 changed files with 293 additions and 158 deletions.
44 changes: 41 additions & 3 deletions consensus/misc/eip1559.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package misc

import (
"encoding/binary"
"fmt"
"math/big"

Expand Down Expand Up @@ -101,18 +102,55 @@ func (f eip1559Calculator) CurrentFees(chainConfig *chain.Config, db kv.Getter)
return baseFee, blobFee, minBlobGasPrice, currentHeader.GasLimit, nil
}

// CalcBaseFee calculates the basefee of the header.
// DecodeHolocene1599Params extracts the Holcene 1599 parameters from the encoded form:
// https://github.com/ethereum-optimism/specs/blob/main/specs/protocol/holocene/exec-engine.md#eip1559params-encoding
func DecodeHolocene1559Params(params types.BlockNonce) (uint64, uint64) {
elasticity := binary.BigEndian.Uint32(params[4:])
denominator := binary.BigEndian.Uint32(params[:4])
return uint64(elasticity), uint64(denominator)
}

func EncodeHolocene1559Params(elasticity, denom uint32) types.BlockNonce {
var nonce types.BlockNonce
binary.BigEndian.PutUint32(nonce[4:], elasticity)
binary.BigEndian.PutUint32(nonce[:4], denom)
return nonce
}

// ValidateHoloceneParams checks if the encoded parameters are valid according to the Holocene
// upgrade.
func ValidateHoloceneParams(params types.BlockNonce) error {
e, d := DecodeHolocene1559Params(params)
if e != 0 && d == 0 {
return fmt.Errorf("holocene params cannot have a 0 denominator unless elasticity is also 0")
}
return nil
}

// The time belongs to the new block to check which upgrades are active.
func CalcBaseFee(config *chain.Config, parent *types.Header, time uint64) *big.Int {
// If the current block is the first EIP-1559 block, return the InitialBaseFee.
if !config.IsLondon(parent.Number.Uint64()) {
return new(big.Int).SetUint64(params.InitialBaseFee)
}

elasticity := config.ElasticityMultiplier(params.ElasticityMultiplier)
denominator := getBaseFeeChangeDenominator(config, params.BaseFeeChangeDenominator, time)

if config.IsHolocene(time) {
// Holocene requires we get the 1559 parameters from the nonce field of the parent header
// unless the field is zero, in which case we use the Canyon values.
if parent.Nonce != types.BlockNonce([8]byte{}) {
elasticity, denominator = DecodeHolocene1559Params(parent.Nonce)
}
}

var (
parentGasTarget = parent.GasLimit / config.ElasticityMultiplier(params.ElasticityMultiplier)
parentGasTarget = parent.GasLimit / elasticity
parentGasTargetBig = new(big.Int).SetUint64(parentGasTarget)
baseFeeChangeDenominator = new(big.Int).SetUint64(getBaseFeeChangeDenominator(config, parent.Number.Uint64(), time))
baseFeeChangeDenominator = new(big.Int).SetUint64(denominator)
)

// If the parent gasUsed is the same as the target, the baseFee remains unchanged.
if parent.GasUsed == parentGasTarget {
return new(big.Int).Set(parent.BaseFee)
Expand Down
44 changes: 44 additions & 0 deletions consensus/misc/eip1559_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ func opConfig() *chain.Config {
EIP1559Denominator: 50,
EIP1559DenominatorCanyon: 250,
}
ht := big.NewInt(12)
config.HoloceneTime = ht
return config
}

Expand Down Expand Up @@ -157,5 +159,47 @@ func TestCalcBaseFeeOptimism(t *testing.T) {
if have, want := CalcBaseFee(opConfig(), parent, parent.Time+2), big.NewInt(test.expectedBaseFee); have.Cmp(want) != 0 {
t.Errorf("test %d: have %d want %d, ", i, have, want)
}
if test.postCanyon {
// make sure Holocene activation doesn't change the outcome; since these tests have a
// zero nonce, they should be handled using the Canyon config.
parent.Time = 10
if have, want := CalcBaseFee(opConfig(), parent, parent.Time+2), big.NewInt(test.expectedBaseFee); have.Cmp(want) != 0 {
t.Errorf("test %d: have %d want %d, ", i, have, want)
}
}
}
}

// TestCalcBaseFeeHolocene assumes all blocks are Optimism blocks post-Holocene upgrade
func TestCalcBaseFeeOptimismHolocene(t *testing.T) {
elasticity2Denom10Nonce := EncodeHolocene1559Params(2, 10)
elasticity10Denom2Nonce := EncodeHolocene1559Params(10, 2)
parentBaseFee := int64(10_000_000)
parentGasLimit := uint64(30_000_000)

tests := []struct {
parentGasUsed uint64
expectedBaseFee int64
nonce types.BlockNonce
}{
{parentGasLimit / 2, parentBaseFee, elasticity2Denom10Nonce}, // target
{10_000_000, 9_666_667, elasticity2Denom10Nonce}, // below
{20_000_000, 10_333_333, elasticity2Denom10Nonce}, // above
{parentGasLimit / 10, parentBaseFee, elasticity10Denom2Nonce}, // target
{1_000_000, 6_666_667, elasticity10Denom2Nonce}, // below
{30_000_000, 55_000_000, elasticity10Denom2Nonce}, // above
}
for i, test := range tests {
parent := &types.Header{
Number: common.Big32,
GasLimit: parentGasLimit,
GasUsed: test.parentGasUsed,
BaseFee: big.NewInt(parentBaseFee),
Time: 10,
Nonce: test.nonce,
}
if have, want := CalcBaseFee(opConfig(), parent, parent.Time+2), big.NewInt(test.expectedBaseFee); have.Cmp(want) != 0 {
t.Errorf("test %d: have %d want %d, ", i, have, want)
}
}
}
1 change: 1 addition & 0 deletions core/block_builder_parameters.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ type BlockBuilderParameters struct {
Transactions [][]byte
NoTxPool bool
GasLimit *uint64
EIP1559Params []byte
}
Loading

0 comments on commit 77950b7

Please sign in to comment.