Skip to content

Commit

Permalink
fix: replace header type in baseFee calc
Browse files Browse the repository at this point in the history
  • Loading branch information
paologalligit committed Dec 12, 2024
1 parent 0124f10 commit 214555e
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 41 deletions.
47 changes: 26 additions & 21 deletions consensus/fork/galactica.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,32 +12,33 @@ import (

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core/types"
"github.com/vechain/thor/v2/block"
"github.com/vechain/thor/v2/thor"
"github.com/vechain/thor/v2/vm"
)

// VerifyGalacticaHeader verifies some header attributes which were changed in Galactica fork,
// - gas limit check
// - basefee check
func VerifyGalacticaHeader(config *vm.ChainConfig, parent, header *types.Header) error {
func VerifyGalacticaHeader(config *vm.ChainConfig, parent, header *block.Header) error {
// Verify that the gas limit remains within allowed bounds
parentGasLimit := parent.GasLimit
if !config.IsGalactica(parent.Number) {
parentGasLimit = parent.GasLimit * thor.ElasticityMultiplier
parentBlockNum := big.NewInt(int64(parent.Number()))
parentGasLimit := parent.GasLimit()
if !config.IsGalactica(parentBlockNum) {
parentGasLimit = parent.GasLimit() * thor.ElasticityMultiplier
}
if err := VerifyGaslimit(parentGasLimit, header.GasLimit); err != nil {
if err := VerifyGaslimit(parentGasLimit, header.GasLimit()); err != nil {
return err
}
// Verify the header is not malformed
if header.BaseFee == nil {
if header.BaseFee() == nil {
return fmt.Errorf("header is missing baseFee")
}
// Verify the baseFee is correct based on the parent header.
expectedBaseFee := CalcBaseFee(config, parent)
if header.BaseFee.Cmp(expectedBaseFee) != 0 {
if header.BaseFee().Cmp(expectedBaseFee) != 0 {
return fmt.Errorf("invalid baseFee: have %s, want %s, parentBaseFee %s, parentGasUsed %d",
expectedBaseFee, header.BaseFee, parent.BaseFee, parent.GasUsed)
expectedBaseFee, header.BaseFee(), parent.BaseFee(), parent.GasUsed())
}
return nil
}
Expand All @@ -61,41 +62,45 @@ func VerifyGaslimit(parentGasLimit, headerGasLimit uint64) error {
}

// CalcBaseFee calculates the basefee of the header.
func CalcBaseFee(config *vm.ChainConfig, parent *types.Header) *big.Int {
func CalcBaseFee(config *vm.ChainConfig, parent *block.Header) *big.Int {
// If the current block is the first Galactica block, return the InitialBaseFee.
if !config.IsGalactica(parent.Number) {
parentBlockNum := big.NewInt(int64(parent.Number()))
if !config.IsGalactica(parentBlockNum) {
return new(big.Int).SetUint64(thor.InitialBaseFee)
}

var (
parentGasTarget = parent.GasLimit / thor.ElasticityMultiplier
parentGasTarget = parent.GasLimit() / thor.ElasticityMultiplier
parentGasTargetBig = new(big.Int).SetUint64(parentGasTarget)
baseFeeChangeDenominator = new(big.Int).SetUint64(thor.BaseFeeChangeDenominator)
)
parentGasUsed := parent.GasUsed()
parentBaseFee := parent.BaseFee()

// 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)
if parentGasUsed == parentGasTarget {
return new(big.Int).Set(parentBaseFee)
}
if parent.GasUsed > parentGasTarget {
if parentGasUsed > parentGasTarget {
// If the parent block used more gas than its target, the baseFee should increase.
gasUsedDelta := new(big.Int).SetUint64(parent.GasUsed - parentGasTarget)
x := new(big.Int).Mul(parent.BaseFee, gasUsedDelta)
gasUsedDelta := new(big.Int).SetUint64(parentGasUsed - parentGasTarget)
x := new(big.Int).Mul(parentBaseFee, gasUsedDelta)
y := x.Div(x, parentGasTargetBig)
baseFeeDelta := math.BigMax(
x.Div(y, baseFeeChangeDenominator),
common.Big1,
)

return x.Add(parent.BaseFee, baseFeeDelta)
return x.Add(parentBaseFee, baseFeeDelta)
} else {
// Otherwise if the parent block used less gas than its target, the baseFee should decrease.
gasUsedDelta := new(big.Int).SetUint64(parentGasTarget - parent.GasUsed)
x := new(big.Int).Mul(parent.BaseFee, gasUsedDelta)
gasUsedDelta := new(big.Int).SetUint64(parentGasTarget - parentGasUsed)
x := new(big.Int).Mul(parentBaseFee, gasUsedDelta)
y := x.Div(x, parentGasTargetBig)
baseFeeDelta := x.Div(y, baseFeeChangeDenominator)

return math.BigMax(
x.Sub(parent.BaseFee, baseFeeDelta),
x.Sub(parentBaseFee, baseFeeDelta),
common.Big0,
)
}
Expand Down
32 changes: 12 additions & 20 deletions consensus/fork/galactica_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
package fork

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

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/vechain/thor/v2/block"
"github.com/vechain/thor/v2/thor"
"github.com/vechain/thor/v2/vm"
)
Expand All @@ -28,7 +28,7 @@ func TestBlockGasLimits(t *testing.T) {

for i, tc := range []struct {
pGasLimit uint64
pNum int64
pNum uint32
gasLimit uint64
ok bool
}{
Expand All @@ -49,18 +49,11 @@ func TestBlockGasLimits(t *testing.T) {
{40000000, 5, 39960939, true}, // lower limit
{40000000, 5, 39960938, false}, // Lower limit -1
} {
parent := &types.Header{
GasUsed: tc.pGasLimit / 2,
GasLimit: tc.pGasLimit,
BaseFee: initial,
Number: big.NewInt(tc.pNum),
}
header := &types.Header{
GasUsed: tc.gasLimit / 2,
GasLimit: tc.gasLimit,
BaseFee: initial,
Number: big.NewInt(tc.pNum + 1),
}
var parentID thor.Bytes32
binary.BigEndian.PutUint32(parentID[:], tc.pNum-1)

parent := new(block.Builder).ParentID(parentID).GasUsed(tc.pGasLimit / 2).GasLimit(tc.pGasLimit).BaseFee(initial).Build().Header()
header := new(block.Builder).ParentID(parent.ID()).GasUsed(tc.gasLimit / 2).GasLimit(tc.gasLimit).BaseFee(initial).Build().Header()
err := VerifyGalacticaHeader(config(), parent, header)
if tc.ok && err != nil {
t.Errorf("test %d: Expected valid header: %s", i, err)
Expand All @@ -84,12 +77,11 @@ func TestCalcBaseFee(t *testing.T) {
{thor.InitialBaseFee, 20000000, 11000000, 1012500000}, // usage above target
}
for i, test := range tests {
parent := &types.Header{
Number: common.Big32,
GasLimit: test.parentGasLimit,
GasUsed: test.parentGasUsed,
BaseFee: big.NewInt(test.parentBaseFee),
b := new(block.Builder).Build()
for j := 0; j < 3; j++ {
b = new(block.Builder).ParentID(b.Header().ID()).GasUsed(test.parentGasUsed).GasLimit(test.parentGasLimit).BaseFee(big.NewInt(test.parentBaseFee)).Build()
}
parent := new(block.Builder).ParentID(b.Header().ID()).GasLimit(test.parentGasLimit).GasUsed(test.parentGasUsed).BaseFee(big.NewInt(test.parentBaseFee)).Build().Header()
if have, want := CalcBaseFee(config(), parent), big.NewInt(test.expectedBaseFee); have.Cmp(want) != 0 {
t.Errorf("test %d: have %d want %d, ", i, have, want)
}
Expand Down

0 comments on commit 214555e

Please sign in to comment.