From fa73a5e424714e08e3f1f5a3e884ab007777004e Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 4 Feb 2025 13:39:43 +0100 Subject: [PATCH] params: move blob count functions to eip4844 --- cmd/evm/internal/t8ntool/execution.go | 2 +- consensus/misc/eip4844/eip4844.go | 65 +++++++++++++++++++++++++- consensus/misc/eip4844/eip4844_test.go | 2 +- core/txpool/blobpool/blobpool.go | 7 +-- core/txpool/validation.go | 6 ++- eth/gasprice/feehistory.go | 3 +- internal/ethapi/transaction_args.go | 2 +- miner/worker.go | 6 +-- params/config.go | 61 ------------------------ tests/state_test_util.go | 2 +- 10 files changed, 80 insertions(+), 76 deletions(-) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 05218bb460..9332f4901b 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -242,7 +242,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, txBlobGas := uint64(0) if tx.Type() == types.BlobTxType { 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 { err := fmt.Errorf("blob gas (%d) would exceed maximum allowance %d", used, max) log.Warn("rejected tx", "index", i, "err", err) diff --git a/consensus/misc/eip4844/eip4844.go b/consensus/misc/eip4844/eip4844.go index b9b8230a80..da1240778e 100644 --- a/consensus/misc/eip4844/eip4844.go +++ b/consensus/misc/eip4844/eip4844.go @@ -42,7 +42,7 @@ func VerifyEIP4844Header(config *params.ChainConfig, parent, header *types.Heade return errors.New("header is missing blobGasUsed") } // Verify that the blob gas used remains within reasonable limits. - maxBlobGas := config.MaxBlobGasPerBlock(header.Time) + maxBlobGas := MaxBlobGasPerBlock(config, header.Time) if *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. func CalcExcessBlobGas(config *params.ChainConfig, parent *types.Header) uint64 { var ( - targetGas = uint64(config.TargetBlobsPerBlock(parent.Time)) * params.BlobTxBlobGasPerBlob + targetGas = uint64(TargetBlobsPerBlock(config, parent.Time)) * params.BlobTxBlobGasPerBlob parentExcessBlobGas 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 // Taylor expansion. func fakeExponential(factor, numerator, denominator *big.Int) *big.Int { diff --git a/consensus/misc/eip4844/eip4844_test.go b/consensus/misc/eip4844/eip4844_test.go index 1ad3f98937..e8f7751067 100644 --- a/consensus/misc/eip4844/eip4844_test.go +++ b/consensus/misc/eip4844/eip4844_test.go @@ -28,7 +28,7 @@ import ( func TestCalcExcessBlobGas(t *testing.T) { var ( config = params.MainnetChainConfig - targetBlobs = config.TargetBlobsPerBlock(*config.CancunTime) + targetBlobs = TargetBlobsPerBlock(config, *config.CancunTime) targetBlobGas = uint64(targetBlobs) * params.BlobTxBlobGasPerBlob ) var tests = []struct { diff --git a/core/txpool/blobpool/blobpool.go b/core/txpool/blobpool/blobpool.go index 4444fd3e4f..78cf2c05af 100644 --- a/core/txpool/blobpool/blobpool.go +++ b/core/txpool/blobpool/blobpool.go @@ -387,7 +387,7 @@ func (p *BlobPool) Init(gasTip uint64, head *types.Header, reserve txpool.Addres 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) if err != nil { 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 // 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 { p.Close() 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(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 oversizedDatagaps += slotDatagaps oversizedSlotused += shelf.FilledSlots diff --git a/core/txpool/validation.go b/core/txpool/validation.go index d155801c97..d0cec04432 100644 --- a/core/txpool/validation.go +++ b/core/txpool/validation.go @@ -23,6 +23,7 @@ import ( "math/big" "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/state" "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 { return errors.New("blobless blob transaction") } - if max := opts.Config.MaxBlobsPerBlock(head.Time); len(hashes) > max { - return fmt.Errorf("too many blobs in transaction: have %d, permitted %d", len(hashes), max) + maxBlobs := eip4844.MaxBlobsPerBlock(opts.Config, head.Time) + 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 if err := validateBlobSidecar(hashes, sidecar); err != nil { diff --git a/eth/gasprice/feehistory.go b/eth/gasprice/feehistory.go index e4019afb56..697263f20b 100644 --- a/eth/gasprice/feehistory.go +++ b/eth/gasprice/feehistory.go @@ -107,7 +107,8 @@ func (oracle *Oracle) processBlock(bf *blockFees, percentiles []float64) { // Compute gas used ratio for normal and blob gas. bf.results.gasUsedRatio = float64(bf.header.GasUsed) / float64(bf.header.GasLimit) 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 { diff --git a/internal/ethapi/transaction_args.go b/internal/ethapi/transaction_args.go index 7c156da01d..7a7d63c535 100644 --- a/internal/ethapi/transaction_args.go +++ b/internal/ethapi/transaction_args.go @@ -121,7 +121,7 @@ func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend, skipGas if args.BlobHashes != nil && len(args.BlobHashes) == 0 { 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 { return fmt.Errorf(`too many blobs in transaction (have=%d, max=%d)`, len(args.BlobHashes), maxBlobs) } diff --git a/miner/worker.go b/miner/worker.go index 9f6efa220a..f8f4bae833 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -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 // 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. - maxBlobs := miner.chainConfig.MaxBlobsPerBlock(env.header.Time) + maxBlobs := eip4844.MaxBlobsPerBlock(miner.chainConfig, env.header.Time) if env.blobs+len(sc.Blobs) > maxBlobs { 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, // 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") blobTxs.Clear() // 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 // a defined schedule, so we need to verify it's safe to call. 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) { log.Trace("Not enough blob space left for transaction", "hash", ltx.Hash, "left", left, "needed", ltx.BlobGas/params.BlobTxBlobGasPerBlob) txs.Pop() diff --git a/params/config.go b/params/config.go index 21b366f9be..59c773b121 100644 --- a/params/config.go +++ b/params/config.go @@ -491,67 +491,6 @@ type BlobScheduleConfig struct { 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. func (c *ChainConfig) IsHomestead(num *big.Int) bool { return isBlockForked(c.HomesteadBlock, num) diff --git a/tests/state_test_util.go b/tests/state_test_util.go index b0ba95bec2..24caf41ed9 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -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 // utilize those codepaths. 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") } }