consensus/misc/eip4844: port to config2

This commit is contained in:
Felix Lange 2025-07-16 01:15:41 +02:00
parent cab21e0b0a
commit 9268b84142
2 changed files with 56 additions and 83 deletions

View file

@ -20,9 +20,11 @@ import (
"errors" "errors"
"fmt" "fmt"
"math/big" "math/big"
"slices"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/params/forks"
) )
var ( var (
@ -32,7 +34,7 @@ var (
// VerifyEIP4844Header verifies the presence of the excessBlobGas field and that // VerifyEIP4844Header verifies the presence of the excessBlobGas field and that
// if the current block contains no transactions, the excessBlobGas is updated // if the current block contains no transactions, the excessBlobGas is updated
// accordingly. // accordingly.
func VerifyEIP4844Header(config *params.ChainConfig, parent, header *types.Header) error { func VerifyEIP4844Header(config *params.Config2, parent, header *types.Header) error {
if header.Number.Uint64() != parent.Number.Uint64()+1 { if header.Number.Uint64() != parent.Number.Uint64()+1 {
panic("bad header pair") panic("bad header pair")
} }
@ -61,7 +63,7 @@ func VerifyEIP4844Header(config *params.ChainConfig, parent, header *types.Heade
// CalcExcessBlobGas calculates the excess blob gas after applying the set of // CalcExcessBlobGas calculates the excess blob gas after applying the set of
// blobs on top of the excess blob gas. // blobs on top of the excess blob gas.
func CalcExcessBlobGas(config *params.ChainConfig, parent *types.Header, headTimestamp uint64) uint64 { func CalcExcessBlobGas(config *params.Config2, parent *types.Header, headTimestamp uint64) uint64 {
var ( var (
parentExcessBlobGas uint64 parentExcessBlobGas uint64
parentBlobGasUsed uint64 parentBlobGasUsed uint64
@ -78,7 +80,7 @@ func CalcExcessBlobGas(config *params.ChainConfig, parent *types.Header, headTim
if excessBlobGas < targetGas { if excessBlobGas < targetGas {
return 0 return 0
} }
if !config.IsOsaka(config.LondonBlock, headTimestamp) { if !config.Active(forks.Osaka, parent.Number.Uint64()+1, headTimestamp) {
// Pre-Osaka, we use the formula defined by EIP-4844. // Pre-Osaka, we use the formula defined by EIP-4844.
return excessBlobGas - targetGas return excessBlobGas - targetGas
} }
@ -98,94 +100,53 @@ func CalcExcessBlobGas(config *params.ChainConfig, parent *types.Header, headTim
} }
// CalcBlobFee calculates the blobfee from the header's excess blob gas field. // CalcBlobFee calculates the blobfee from the header's excess blob gas field.
func CalcBlobFee(config *params.ChainConfig, header *types.Header) *big.Int { func CalcBlobFee(config *params.Config2, header *types.Header) *big.Int {
blobConfig := latestBlobConfig(config, header.Time) schedule := params.Get[params.BlobSchedule](config)
if blobConfig == nil { if schedule == nil {
panic("calculating blob fee on unsupported fork") return new(big.Int)
} }
return fakeExponential(minBlobGasPrice, new(big.Int).SetUint64(*header.ExcessBlobGas), new(big.Int).SetUint64(blobConfig.UpdateFraction)) f := config.LatestFork(header.Time)
frac := schedule[f].UpdateFraction
return fakeExponential(minBlobGasPrice, new(big.Int).SetUint64(*header.ExcessBlobGas), new(big.Int).SetUint64(frac))
} }
// MaxBlobsPerBlock returns the max blobs per block for a block at the given timestamp. // MaxBlobsPerBlock returns the max blobs per block for a block at the given timestamp.
func MaxBlobsPerBlock(cfg *params.ChainConfig, time uint64) int { func MaxBlobsPerBlock(cfg *params.Config2, time uint64) int {
blobConfig := latestBlobConfig(cfg, time) return scheduleAtTime(cfg, time).Max
if blobConfig == nil {
return 0
}
return blobConfig.Max
} }
func latestBlobConfig(cfg *params.ChainConfig, time uint64) *params.BlobConfig { // MaxBlobsPerBlock returns the maximum blob gas that can be spent in a block at the given timestamp.
if cfg.BlobScheduleConfig == nil { func MaxBlobGasPerBlock(cfg *params.Config2, time uint64) uint64 {
return nil
}
var (
london = cfg.LondonBlock
s = cfg.BlobScheduleConfig
)
switch {
case cfg.IsBPO5(london, time) && s.BPO5 != nil:
return s.BPO5
case cfg.IsBPO4(london, time) && s.BPO4 != nil:
return s.BPO4
case cfg.IsBPO3(london, time) && s.BPO3 != nil:
return s.BPO3
case cfg.IsBPO2(london, time) && s.BPO2 != nil:
return s.BPO2
case cfg.IsBPO1(london, time) && s.BPO1 != nil:
return s.BPO1
case cfg.IsOsaka(london, time) && s.Osaka != nil:
return s.Osaka
case cfg.IsPrague(london, time) && s.Prague != nil:
return s.Prague
case cfg.IsCancun(london, time) && s.Cancun != nil:
return s.Cancun
default:
return nil
}
}
// MaxBlobGasPerBlock returns the maximum blob gas that can be spent in a block at the given timestamp.
func MaxBlobGasPerBlock(cfg *params.ChainConfig, time uint64) uint64 {
return uint64(MaxBlobsPerBlock(cfg, time)) * params.BlobTxBlobGasPerBlob return uint64(MaxBlobsPerBlock(cfg, time)) * params.BlobTxBlobGasPerBlob
} }
// LatestMaxBlobsPerBlock returns the latest max blobs per block defined by the // LatestMaxBlobsPerBlock returns the latest max blobs per block defined by the
// configuration, regardless of the currently active fork. // configuration, regardless of the currently active fork.
func LatestMaxBlobsPerBlock(cfg *params.ChainConfig) int { func LatestMaxBlobsPerBlock(cfg *params.Config2) int {
s := cfg.BlobScheduleConfig schedule := params.Get[params.BlobSchedule](cfg)
if s == nil { if schedule == nil {
return 0 return 0
} }
switch { for _, f := range slices.Backward(forks.CanonOrder) {
case s.BPO5 != nil: if f.HasBlobs() && cfg.Scheduled(f) {
return s.BPO5.Max return schedule[f].Max
case s.BPO4 != nil:
return s.BPO4.Max
case s.BPO3 != nil:
return s.BPO3.Max
case s.BPO2 != nil:
return s.BPO2.Max
case s.BPO1 != nil:
return s.BPO1.Max
case s.Osaka != nil:
return s.Osaka.Max
case s.Prague != nil:
return s.Prague.Max
case s.Cancun != nil:
return s.Cancun.Max
default:
return 0
} }
}
return 0
} }
// targetBlobsPerBlock returns the target number of blobs in a block at the given timestamp. // targetBlobsPerBlock returns the target number of blobs in a block at the given timestamp.
func targetBlobsPerBlock(cfg *params.ChainConfig, time uint64) int { func targetBlobsPerBlock(cfg *params.Config2, time uint64) int {
blobConfig := latestBlobConfig(cfg, time) return scheduleAtTime(cfg, time).Target
if blobConfig == nil { }
return 0
func scheduleAtTime(cfg *params.Config2, time uint64) params.BlobConfig {
schedule := params.Get[params.BlobSchedule](cfg)
if schedule == nil {
return params.BlobConfig{}
} }
return blobConfig.Target f := cfg.LatestFork(time)
return schedule[f]
} }
// fakeExponential approximates factor * e ** (numerator / denominator) using // fakeExponential approximates factor * e ** (numerator / denominator) using
@ -206,7 +167,7 @@ func fakeExponential(factor, numerator, denominator *big.Int) *big.Int {
} }
// calcBlobPrice calculates the blob price for a block. // calcBlobPrice calculates the blob price for a block.
func calcBlobPrice(config *params.ChainConfig, header *types.Header) *big.Int { func calcBlobPrice(config *params.Config2, header *types.Header) *big.Int {
blobBaseFee := CalcBlobFee(config, header) blobBaseFee := CalcBlobFee(config, header)
return new(big.Int).Mul(blobBaseFee, big.NewInt(params.BlobTxBlobGasPerBlob)) return new(big.Int).Mul(blobBaseFee, big.NewInt(params.BlobTxBlobGasPerBlob))
} }

View file

@ -23,12 +23,15 @@ import (
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/params/forks"
"github.com/ethereum/go-ethereum/params/presets"
) )
func TestCalcExcessBlobGas(t *testing.T) { func TestCalcExcessBlobGas(t *testing.T) {
var ( var (
config = params.MainnetChainConfig config = presets.Mainnet
targetBlobs = targetBlobsPerBlock(config, *config.CancunTime) cancunTime, _ = config.Activation(forks.Cancun)
targetBlobs = targetBlobsPerBlock(config, cancunTime)
targetBlobGas = uint64(targetBlobs) * params.BlobTxBlobGasPerBlob targetBlobGas = uint64(targetBlobs) * params.BlobTxBlobGasPerBlob
) )
var tests = []struct { var tests = []struct {
@ -58,10 +61,11 @@ func TestCalcExcessBlobGas(t *testing.T) {
for i, tt := range tests { for i, tt := range tests {
blobGasUsed := uint64(tt.blobs) * params.BlobTxBlobGasPerBlob blobGasUsed := uint64(tt.blobs) * params.BlobTxBlobGasPerBlob
header := &types.Header{ header := &types.Header{
Number: big.NewInt(1),
ExcessBlobGas: &tt.excess, ExcessBlobGas: &tt.excess,
BlobGasUsed: &blobGasUsed, BlobGasUsed: &blobGasUsed,
} }
result := CalcExcessBlobGas(config, header, *config.CancunTime) result := CalcExcessBlobGas(config, header, cancunTime)
if result != tt.want { if result != tt.want {
t.Errorf("test %d: excess blob gas mismatch: have %v, want %v", i, result, tt.want) t.Errorf("test %d: excess blob gas mismatch: have %v, want %v", i, result, tt.want)
} }
@ -69,8 +73,6 @@ func TestCalcExcessBlobGas(t *testing.T) {
} }
func TestCalcBlobFee(t *testing.T) { func TestCalcBlobFee(t *testing.T) {
zero := uint64(0)
tests := []struct { tests := []struct {
excessBlobGas uint64 excessBlobGas uint64
blobfee int64 blobfee int64
@ -81,7 +83,15 @@ func TestCalcBlobFee(t *testing.T) {
{10 * 1024 * 1024, 23}, {10 * 1024 * 1024, 23},
} }
for i, tt := range tests { for i, tt := range tests {
config := &params.ChainConfig{LondonBlock: big.NewInt(0), CancunTime: &zero, BlobScheduleConfig: params.DefaultBlobSchedule} config := params.NewConfig2(
params.Activations{
forks.London: 0,
forks.Cancun: 0,
},
params.BlobSchedule{
forks.Cancun: *params.DefaultCancunBlobConfig,
},
)
header := &types.Header{ExcessBlobGas: &tt.excessBlobGas} header := &types.Header{ExcessBlobGas: &tt.excessBlobGas}
have := CalcBlobFee(config, header) have := CalcBlobFee(config, header)
if have.Int64() != tt.blobfee { if have.Int64() != tt.blobfee {
@ -130,13 +140,15 @@ func TestFakeExponential(t *testing.T) {
func TestCalcExcessBlobGasEIP7918(t *testing.T) { func TestCalcExcessBlobGasEIP7918(t *testing.T) {
var ( var (
cfg = params.MergedTestChainConfig cfg = presets.MergedTestChainConfig
targetBlobs = targetBlobsPerBlock(cfg, *cfg.CancunTime) cancunTime, _ = cfg.Activation(forks.Cancun)
targetBlobs = targetBlobsPerBlock(cfg, cancunTime)
blobGasTarget = uint64(targetBlobs) * params.BlobTxBlobGasPerBlob blobGasTarget = uint64(targetBlobs) * params.BlobTxBlobGasPerBlob
) )
makeHeader := func(parentExcess, parentBaseFee uint64, blobsUsed int) *types.Header { makeHeader := func(parentExcess, parentBaseFee uint64, blobsUsed int) *types.Header {
blobGasUsed := uint64(blobsUsed) * params.BlobTxBlobGasPerBlob blobGasUsed := uint64(blobsUsed) * params.BlobTxBlobGasPerBlob
return &types.Header{ return &types.Header{
Number: big.NewInt(1),
BaseFee: big.NewInt(int64(parentBaseFee)), BaseFee: big.NewInt(int64(parentBaseFee)),
ExcessBlobGas: &parentExcess, ExcessBlobGas: &parentExcess,
BlobGasUsed: &blobGasUsed, BlobGasUsed: &blobGasUsed,
@ -160,7 +172,7 @@ func TestCalcExcessBlobGasEIP7918(t *testing.T) {
}, },
} }
for _, tc := range tests { for _, tc := range tests {
got := CalcExcessBlobGas(cfg, tc.header, *cfg.CancunTime) got := CalcExcessBlobGas(cfg, tc.header, cancunTime)
if got != tc.wantExcessGas { if got != tc.wantExcessGas {
t.Fatalf("%s: excess-blob-gas mismatch have %d, want %d", t.Fatalf("%s: excess-blob-gas mismatch have %d, want %d",
tc.name, got, tc.wantExcessGas) tc.name, got, tc.wantExcessGas)