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"
"fmt"
"math/big"
"slices"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/params/forks"
)
var (
@ -32,7 +34,7 @@ var (
// VerifyEIP4844Header verifies the presence of the excessBlobGas field and that
// if the current block contains no transactions, the excessBlobGas is updated
// 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 {
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
// 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 (
parentExcessBlobGas uint64
parentBlobGasUsed uint64
@ -78,7 +80,7 @@ func CalcExcessBlobGas(config *params.ChainConfig, parent *types.Header, headTim
if excessBlobGas < targetGas {
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.
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.
func CalcBlobFee(config *params.ChainConfig, header *types.Header) *big.Int {
blobConfig := latestBlobConfig(config, header.Time)
if blobConfig == nil {
panic("calculating blob fee on unsupported fork")
func CalcBlobFee(config *params.Config2, header *types.Header) *big.Int {
schedule := params.Get[params.BlobSchedule](config)
if schedule == nil {
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.
func MaxBlobsPerBlock(cfg *params.ChainConfig, time uint64) int {
blobConfig := latestBlobConfig(cfg, time)
if blobConfig == nil {
return 0
}
return blobConfig.Max
func MaxBlobsPerBlock(cfg *params.Config2, time uint64) int {
return scheduleAtTime(cfg, time).Max
}
func latestBlobConfig(cfg *params.ChainConfig, time uint64) *params.BlobConfig {
if cfg.BlobScheduleConfig == nil {
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 {
// MaxBlobsPerBlock returns the maximum blob gas that can be spent in a block at the given timestamp.
func MaxBlobGasPerBlock(cfg *params.Config2, time uint64) uint64 {
return uint64(MaxBlobsPerBlock(cfg, time)) * params.BlobTxBlobGasPerBlob
}
// LatestMaxBlobsPerBlock returns the latest max blobs per block defined by the
// configuration, regardless of the currently active fork.
func LatestMaxBlobsPerBlock(cfg *params.ChainConfig) int {
s := cfg.BlobScheduleConfig
if s == nil {
func LatestMaxBlobsPerBlock(cfg *params.Config2) int {
schedule := params.Get[params.BlobSchedule](cfg)
if schedule == nil {
return 0
}
switch {
case s.BPO5 != nil:
return s.BPO5.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
for _, f := range slices.Backward(forks.CanonOrder) {
if f.HasBlobs() && cfg.Scheduled(f) {
return schedule[f].Max
}
}
return 0
}
// targetBlobsPerBlock returns the target number of blobs in a block at the given timestamp.
func targetBlobsPerBlock(cfg *params.ChainConfig, time uint64) int {
blobConfig := latestBlobConfig(cfg, time)
if blobConfig == nil {
return 0
func targetBlobsPerBlock(cfg *params.Config2, time uint64) int {
return scheduleAtTime(cfg, time).Target
}
return blobConfig.Target
func scheduleAtTime(cfg *params.Config2, time uint64) params.BlobConfig {
schedule := params.Get[params.BlobSchedule](cfg)
if schedule == nil {
return params.BlobConfig{}
}
f := cfg.LatestFork(time)
return schedule[f]
}
// 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.
func calcBlobPrice(config *params.ChainConfig, header *types.Header) *big.Int {
func calcBlobPrice(config *params.Config2, header *types.Header) *big.Int {
blobBaseFee := CalcBlobFee(config, header)
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/params"
"github.com/ethereum/go-ethereum/params/forks"
"github.com/ethereum/go-ethereum/params/presets"
)
func TestCalcExcessBlobGas(t *testing.T) {
var (
config = params.MainnetChainConfig
targetBlobs = targetBlobsPerBlock(config, *config.CancunTime)
config = presets.Mainnet
cancunTime, _ = config.Activation(forks.Cancun)
targetBlobs = targetBlobsPerBlock(config, cancunTime)
targetBlobGas = uint64(targetBlobs) * params.BlobTxBlobGasPerBlob
)
var tests = []struct {
@ -58,10 +61,11 @@ func TestCalcExcessBlobGas(t *testing.T) {
for i, tt := range tests {
blobGasUsed := uint64(tt.blobs) * params.BlobTxBlobGasPerBlob
header := &types.Header{
Number: big.NewInt(1),
ExcessBlobGas: &tt.excess,
BlobGasUsed: &blobGasUsed,
}
result := CalcExcessBlobGas(config, header, *config.CancunTime)
result := CalcExcessBlobGas(config, header, cancunTime)
if 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) {
zero := uint64(0)
tests := []struct {
excessBlobGas uint64
blobfee int64
@ -81,7 +83,15 @@ func TestCalcBlobFee(t *testing.T) {
{10 * 1024 * 1024, 23},
}
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}
have := CalcBlobFee(config, header)
if have.Int64() != tt.blobfee {
@ -130,13 +140,15 @@ func TestFakeExponential(t *testing.T) {
func TestCalcExcessBlobGasEIP7918(t *testing.T) {
var (
cfg = params.MergedTestChainConfig
targetBlobs = targetBlobsPerBlock(cfg, *cfg.CancunTime)
cfg = presets.MergedTestChainConfig
cancunTime, _ = cfg.Activation(forks.Cancun)
targetBlobs = targetBlobsPerBlock(cfg, cancunTime)
blobGasTarget = uint64(targetBlobs) * params.BlobTxBlobGasPerBlob
)
makeHeader := func(parentExcess, parentBaseFee uint64, blobsUsed int) *types.Header {
blobGasUsed := uint64(blobsUsed) * params.BlobTxBlobGasPerBlob
return &types.Header{
Number: big.NewInt(1),
BaseFee: big.NewInt(int64(parentBaseFee)),
ExcessBlobGas: &parentExcess,
BlobGasUsed: &blobGasUsed,
@ -160,7 +172,7 @@ func TestCalcExcessBlobGasEIP7918(t *testing.T) {
},
}
for _, tc := range tests {
got := CalcExcessBlobGas(cfg, tc.header, *cfg.CancunTime)
got := CalcExcessBlobGas(cfg, tc.header, cancunTime)
if got != tc.wantExcessGas {
t.Fatalf("%s: excess-blob-gas mismatch have %d, want %d",
tc.name, got, tc.wantExcessGas)