params: move blob count functions to eip4844

This commit is contained in:
Felix Lange 2025-02-04 13:39:43 +01:00
parent 28496b0180
commit fa73a5e424
10 changed files with 80 additions and 76 deletions

View file

@ -242,7 +242,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
txBlobGas := uint64(0) txBlobGas := uint64(0)
if tx.Type() == types.BlobTxType { if tx.Type() == types.BlobTxType {
txBlobGas = uint64(params.BlobTxBlobGasPerBlob * len(tx.BlobHashes())) txBlobGas = uint64(params.BlobTxBlobGasPerBlob * len(tx.BlobHashes()))
max := chainConfig.MaxBlobGasPerBlock(pre.Env.Timestamp) max := eip4844.MaxBlobGasPerBlock(chainConfig, pre.Env.Timestamp)
if used := blobGasUsed + txBlobGas; used > max { if used := blobGasUsed + txBlobGas; used > max {
err := fmt.Errorf("blob gas (%d) would exceed maximum allowance %d", used, max) err := fmt.Errorf("blob gas (%d) would exceed maximum allowance %d", used, max)
log.Warn("rejected tx", "index", i, "err", err) log.Warn("rejected tx", "index", i, "err", err)

View file

@ -42,7 +42,7 @@ func VerifyEIP4844Header(config *params.ChainConfig, parent, header *types.Heade
return errors.New("header is missing blobGasUsed") return errors.New("header is missing blobGasUsed")
} }
// Verify that the blob gas used remains within reasonable limits. // Verify that the blob gas used remains within reasonable limits.
maxBlobGas := config.MaxBlobGasPerBlock(header.Time) maxBlobGas := MaxBlobGasPerBlock(config, header.Time)
if *header.BlobGasUsed > maxBlobGas { if *header.BlobGasUsed > maxBlobGas {
return fmt.Errorf("blob gas used %d exceeds maximum allowance %d", *header.BlobGasUsed, maxBlobGas) return fmt.Errorf("blob gas used %d exceeds maximum allowance %d", *header.BlobGasUsed, maxBlobGas)
} }
@ -61,7 +61,7 @@ func VerifyEIP4844Header(config *params.ChainConfig, parent, header *types.Heade
// blobs on top of the excess blob gas. // blobs on top of the excess blob gas.
func CalcExcessBlobGas(config *params.ChainConfig, parent *types.Header) uint64 { func CalcExcessBlobGas(config *params.ChainConfig, parent *types.Header) uint64 {
var ( var (
targetGas = uint64(config.TargetBlobsPerBlock(parent.Time)) * params.BlobTxBlobGasPerBlob targetGas = uint64(TargetBlobsPerBlock(config, parent.Time)) * params.BlobTxBlobGasPerBlob
parentExcessBlobGas uint64 parentExcessBlobGas uint64
parentBlobGasUsed uint64 parentBlobGasUsed uint64
) )
@ -88,6 +88,67 @@ func CalcBlobFee(config *params.ChainConfig, header *types.Header) *big.Int {
} }
} }
// TargetBlobsPerBlock returns the target blobs per block associated with
// requested time.
func TargetBlobsPerBlock(cfg *params.ChainConfig, time uint64) int {
if cfg.BlobScheduleConfig == nil {
return 0
}
var (
london = cfg.LondonBlock
s = cfg.BlobScheduleConfig
)
switch {
case cfg.IsPrague(london, time) && s.Prague != nil:
return s.Prague.Target
case cfg.IsCancun(london, time) && s.Cancun != nil:
return s.Cancun.Target
default:
return 0
}
}
// MaxBlobsPerBlock returns the max blobs per block for a block at the given timestamp.
func MaxBlobsPerBlock(cfg *params.ChainConfig, time uint64) int {
if cfg.BlobScheduleConfig == nil {
return 0
}
var (
london = cfg.LondonBlock
s = cfg.BlobScheduleConfig
)
switch {
case cfg.IsPrague(london, time) && s.Prague != nil:
return s.Prague.Max
case cfg.IsCancun(london, time) && s.Cancun != nil:
return s.Cancun.Max
default:
return 0
}
}
// MaxBlobsPerBlock 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
}
// 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 {
return 0
}
switch {
case s.Prague != nil:
return s.Prague.Max
case s.Cancun != nil:
return s.Cancun.Max
default:
return 0
}
}
// fakeExponential approximates factor * e ** (numerator / denominator) using // fakeExponential approximates factor * e ** (numerator / denominator) using
// Taylor expansion. // Taylor expansion.
func fakeExponential(factor, numerator, denominator *big.Int) *big.Int { func fakeExponential(factor, numerator, denominator *big.Int) *big.Int {

View file

@ -28,7 +28,7 @@ import (
func TestCalcExcessBlobGas(t *testing.T) { func TestCalcExcessBlobGas(t *testing.T) {
var ( var (
config = params.MainnetChainConfig config = params.MainnetChainConfig
targetBlobs = config.TargetBlobsPerBlock(*config.CancunTime) targetBlobs = TargetBlobsPerBlock(config, *config.CancunTime)
targetBlobGas = uint64(targetBlobs) * params.BlobTxBlobGasPerBlob targetBlobGas = uint64(targetBlobs) * params.BlobTxBlobGasPerBlob
) )
var tests = []struct { var tests = []struct {

View file

@ -387,7 +387,7 @@ func (p *BlobPool) Init(gasTip uint64, head *types.Header, reserve txpool.Addres
fails = append(fails, id) fails = append(fails, id)
} }
} }
slotter := newSlotter(p.chain.Config().LatestMaxBlobsPerBlock()) slotter := newSlotter(eip4844.LatestMaxBlobsPerBlock(p.chain.Config()))
store, err := billy.Open(billy.Options{Path: queuedir, Repair: true}, slotter, index) store, err := billy.Open(billy.Options{Path: queuedir, Repair: true}, slotter, index)
if err != nil { if err != nil {
return err return err
@ -421,7 +421,7 @@ func (p *BlobPool) Init(gasTip uint64, head *types.Header, reserve txpool.Addres
// Pool initialized, attach the blob limbo to it to track blobs included // Pool initialized, attach the blob limbo to it to track blobs included
// recently but not yet finalized // recently but not yet finalized
p.limbo, err = newLimbo(limbodir, p.chain.Config().LatestMaxBlobsPerBlock()) p.limbo, err = newLimbo(limbodir, eip4844.LatestMaxBlobsPerBlock(p.chain.Config()))
if err != nil { if err != nil {
p.Close() p.Close()
return err return err
@ -1599,7 +1599,8 @@ func (p *BlobPool) updateStorageMetrics() {
metrics.GetOrRegisterGauge(fmt.Sprintf(shelfSlotusedGaugeName, shelf.SlotSize/blobSize), nil).Update(int64(shelf.FilledSlots)) metrics.GetOrRegisterGauge(fmt.Sprintf(shelfSlotusedGaugeName, shelf.SlotSize/blobSize), nil).Update(int64(shelf.FilledSlots))
metrics.GetOrRegisterGauge(fmt.Sprintf(shelfSlotgapsGaugeName, shelf.SlotSize/blobSize), nil).Update(int64(shelf.GappedSlots)) metrics.GetOrRegisterGauge(fmt.Sprintf(shelfSlotgapsGaugeName, shelf.SlotSize/blobSize), nil).Update(int64(shelf.GappedSlots))
if shelf.SlotSize/blobSize > uint32(p.chain.Config().LatestMaxBlobsPerBlock()) { maxBlobs := eip4844.LatestMaxBlobsPerBlock(p.chain.Config())
if shelf.SlotSize/blobSize > uint32(maxBlobs) {
oversizedDataused += slotDataused oversizedDataused += slotDataused
oversizedDatagaps += slotDatagaps oversizedDatagaps += slotDatagaps
oversizedSlotused += shelf.FilledSlots oversizedSlotused += shelf.FilledSlots

View file

@ -23,6 +23,7 @@ import (
"math/big" "math/big"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
@ -134,8 +135,9 @@ func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types
if len(hashes) == 0 { if len(hashes) == 0 {
return errors.New("blobless blob transaction") return errors.New("blobless blob transaction")
} }
if max := opts.Config.MaxBlobsPerBlock(head.Time); len(hashes) > max { maxBlobs := eip4844.MaxBlobsPerBlock(opts.Config, head.Time)
return fmt.Errorf("too many blobs in transaction: have %d, permitted %d", len(hashes), max) if len(hashes) > maxBlobs {
return fmt.Errorf("too many blobs in transaction: have %d, permitted %d", len(hashes), maxBlobs)
} }
// Ensure commitments, proofs and hashes are valid // Ensure commitments, proofs and hashes are valid
if err := validateBlobSidecar(hashes, sidecar); err != nil { if err := validateBlobSidecar(hashes, sidecar); err != nil {

View file

@ -107,7 +107,8 @@ func (oracle *Oracle) processBlock(bf *blockFees, percentiles []float64) {
// Compute gas used ratio for normal and blob gas. // Compute gas used ratio for normal and blob gas.
bf.results.gasUsedRatio = float64(bf.header.GasUsed) / float64(bf.header.GasLimit) bf.results.gasUsedRatio = float64(bf.header.GasUsed) / float64(bf.header.GasLimit)
if blobGasUsed := bf.header.BlobGasUsed; blobGasUsed != nil { if blobGasUsed := bf.header.BlobGasUsed; blobGasUsed != nil {
bf.results.blobGasUsedRatio = float64(*blobGasUsed) / float64(config.MaxBlobsPerBlock(bf.header.Time)) maxBlobs := eip4844.MaxBlobsPerBlock(config, bf.header.Time)
bf.results.blobGasUsedRatio = float64(*blobGasUsed) / float64(maxBlobs)
} }
if len(percentiles) == 0 { if len(percentiles) == 0 {

View file

@ -121,7 +121,7 @@ func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend, skipGas
if args.BlobHashes != nil && len(args.BlobHashes) == 0 { if args.BlobHashes != nil && len(args.BlobHashes) == 0 {
return errors.New(`need at least 1 blob for a blob transaction`) return errors.New(`need at least 1 blob for a blob transaction`)
} }
maxBlobs := b.ChainConfig().MaxBlobsPerBlock(b.CurrentHeader().Time) maxBlobs := eip4844.MaxBlobsPerBlock(b.ChainConfig(), b.CurrentHeader().Time)
if args.BlobHashes != nil && len(args.BlobHashes) > maxBlobs { if args.BlobHashes != nil && len(args.BlobHashes) > maxBlobs {
return fmt.Errorf(`too many blobs in transaction (have=%d, max=%d)`, len(args.BlobHashes), maxBlobs) return fmt.Errorf(`too many blobs in transaction (have=%d, max=%d)`, len(args.BlobHashes), maxBlobs)
} }

View file

@ -281,7 +281,7 @@ func (miner *Miner) commitBlobTransaction(env *environment, tx *types.Transactio
// isn't really a better place right now. The blob gas limit is checked at block validation time // isn't really a better place right now. The blob gas limit is checked at block validation time
// and not during execution. This means core.ApplyTransaction will not return an error if the // and not during execution. This means core.ApplyTransaction will not return an error if the
// tx has too many blobs. So we have to explicitly check it here. // tx has too many blobs. So we have to explicitly check it here.
maxBlobs := miner.chainConfig.MaxBlobsPerBlock(env.header.Time) maxBlobs := eip4844.MaxBlobsPerBlock(miner.chainConfig, env.header.Time)
if env.blobs+len(sc.Blobs) > maxBlobs { if env.blobs+len(sc.Blobs) > maxBlobs {
return errors.New("max data blobs reached") return errors.New("max data blobs reached")
} }
@ -331,7 +331,7 @@ func (miner *Miner) commitTransactions(env *environment, plainTxs, blobTxs *tran
} }
// If we don't have enough blob space for any further blob transactions, // If we don't have enough blob space for any further blob transactions,
// skip that list altogether // skip that list altogether
if !blobTxs.Empty() && env.blobs >= miner.chainConfig.MaxBlobsPerBlock(env.header.Time) { if !blobTxs.Empty() && env.blobs >= eip4844.MaxBlobsPerBlock(miner.chainConfig, env.header.Time) {
log.Trace("Not enough blob space for further blob transactions") log.Trace("Not enough blob space for further blob transactions")
blobTxs.Clear() blobTxs.Clear()
// Fall though to pick up any plain txs // Fall though to pick up any plain txs
@ -370,7 +370,7 @@ func (miner *Miner) commitTransactions(env *environment, plainTxs, blobTxs *tran
// blobs or not, however the max check panics when called on a chain without // blobs or not, however the max check panics when called on a chain without
// a defined schedule, so we need to verify it's safe to call. // a defined schedule, so we need to verify it's safe to call.
if miner.chainConfig.IsCancun(env.header.Number, env.header.Time) { if miner.chainConfig.IsCancun(env.header.Number, env.header.Time) {
left := miner.chainConfig.MaxBlobsPerBlock(env.header.Time) - env.blobs left := eip4844.MaxBlobsPerBlock(miner.chainConfig, env.header.Time) - env.blobs
if left < int(ltx.BlobGas/params.BlobTxBlobGasPerBlob) { if left < int(ltx.BlobGas/params.BlobTxBlobGasPerBlob) {
log.Trace("Not enough blob space left for transaction", "hash", ltx.Hash, "left", left, "needed", ltx.BlobGas/params.BlobTxBlobGasPerBlob) log.Trace("Not enough blob space left for transaction", "hash", ltx.Hash, "left", left, "needed", ltx.BlobGas/params.BlobTxBlobGasPerBlob)
txs.Pop() txs.Pop()

View file

@ -491,67 +491,6 @@ type BlobScheduleConfig struct {
Verkle *BlobConfig `json:"verkle,omitempty"` Verkle *BlobConfig `json:"verkle,omitempty"`
} }
// TargetBlobsPerBlock returns the target blobs per block associated with
// requested time.
func (c *ChainConfig) TargetBlobsPerBlock(time uint64) int {
if c.BlobScheduleConfig == nil {
return 0
}
var (
london = c.LondonBlock
s = c.BlobScheduleConfig
)
switch {
case c.IsPrague(london, time) && s.Prague != nil:
return s.Prague.Target
case c.IsCancun(london, time) && s.Cancun != nil:
return s.Cancun.Target
default:
return 0
}
}
// MaxBlobsPerBlock returns the max blobs per block for a block at the given timestamp.
func (c *ChainConfig) MaxBlobsPerBlock(time uint64) int {
if c.BlobScheduleConfig == nil {
return 0
}
var (
london = c.LondonBlock
s = c.BlobScheduleConfig
)
switch {
case c.IsPrague(london, time) && s.Prague != nil:
return s.Prague.Max
case c.IsCancun(london, time) && s.Cancun != nil:
return s.Cancun.Max
default:
return 0
}
}
// MaxBlobsPerBlock returns the maximum blob gas that can be spent in a block at the given timestamp.
func (c *ChainConfig) MaxBlobGasPerBlock(time uint64) uint64 {
return uint64(c.MaxBlobsPerBlock(time)) * BlobTxBlobGasPerBlob
}
// LatestMaxBlobsPerBlock returns the latest max blobs per block defined by the
// configuration, regardless of the currently active fork.
func (c *ChainConfig) LatestMaxBlobsPerBlock() int {
s := c.BlobScheduleConfig
if s == nil {
return 0
}
switch {
case s.Prague != nil:
return s.Prague.Max
case s.Cancun != nil:
return s.Cancun.Max
default:
return 0
}
}
// IsHomestead returns whether num is either equal to the homestead block or greater. // IsHomestead returns whether num is either equal to the homestead block or greater.
func (c *ChainConfig) IsHomestead(num *big.Int) bool { func (c *ChainConfig) IsHomestead(num *big.Int) bool {
return isBlockForked(c.HomesteadBlock, num) return isBlockForked(c.HomesteadBlock, num)

View file

@ -283,7 +283,7 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh
// Here, we just do this shortcut smaller fix, since state tests do not // Here, we just do this shortcut smaller fix, since state tests do not
// utilize those codepaths. // utilize those codepaths.
if config.IsCancun(new(big.Int), block.Time()) { if config.IsCancun(new(big.Int), block.Time()) {
if len(msg.BlobHashes) > config.MaxBlobsPerBlock(block.Time()) { if len(msg.BlobHashes) > eip4844.MaxBlobsPerBlock(config, block.Time()) {
return st, common.Hash{}, 0, errors.New("blob gas exceeds maximum") return st, common.Hash{}, 0, errors.New("blob gas exceeds maximum")
} }
} }