Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement EIP-7691 blob gas price changes for pdn-5 #13426

Merged
merged 11 commits into from
Jan 16, 2025
2 changes: 1 addition & 1 deletion accounts/abi/bind/backends/simulated.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ func (b *SimulatedBackend) emptyPendingBlock() {
b.pendingBlock = blockChain.Blocks[0]
b.pendingReceipts = blockChain.Receipts[0]
b.pendingHeader = blockChain.Headers[0]
b.gasPool = new(core.GasPool).AddGas(b.pendingHeader.GasLimit).AddBlobGas(b.m.ChainConfig.GetMaxBlobGasPerBlock())
b.gasPool = new(core.GasPool).AddGas(b.pendingHeader.GasLimit).AddBlobGas(b.m.ChainConfig.GetMaxBlobGasPerBlock(b.pendingHeader.Time))
if b.pendingReaderTx != nil {
b.pendingReaderTx.Rollback()
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/devnet/services/polygon/proofgenerator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ func (rg *requestGenerator) GetTransactionReceipt(ctx context.Context, hash libc
var usedGas uint64
var usedBlobGas uint64

gp := new(core.GasPool).AddGas(block.GasLimit()).AddBlobGas(chainConfig.GetMaxBlobGasPerBlock())
gp := new(core.GasPool).AddGas(block.GasLimit()).AddBlobGas(chainConfig.GetMaxBlobGasPerBlock(block.Header().Time))

noopWriter := state.NewNoopWriter()

Expand Down
2 changes: 1 addition & 1 deletion cmd/state/commands/opcode_tracer.go
Original file line number Diff line number Diff line change
Expand Up @@ -732,7 +732,7 @@ func runBlock(engine consensus.Engine, ibs *state.IntraBlockState, txnWriter sta
chainConfig *chain2.Config, getHeader func(hash libcommon.Hash, number uint64) *types.Header, block *types.Block, vmConfig vm.Config, trace bool, logger log.Logger) (types.Receipts, error) {
header := block.Header()
vmConfig.TraceJumpDest = true
gp := new(core.GasPool).AddGas(block.GasLimit()).AddBlobGas(chainConfig.GetMaxBlobGasPerBlock())
gp := new(core.GasPool).AddGas(block.GasLimit()).AddBlobGas(chainConfig.GetMaxBlobGasPerBlock(header.Time))
usedGas := new(uint64)
usedBlobGas := new(uint64)
var receipts types.Receipts
Expand Down
4 changes: 2 additions & 2 deletions cmd/state/exec3/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ func NewWorker(lock sync.Locker, logger log.Logger, ctx context.Context, backgro

isMining: isMining,
}
w.taskGasPool.AddBlobGas(chainConfig.GetMaxBlobGasPerBlock())
w.taskGasPool.AddBlobGas(chainConfig.GetMaxBlobGasPerBlock(0))
w.vmCfg = vm.Config{Debug: true, Tracer: w.callTracer}
w.ibs = state.New(w.stateReader)
return w
Expand Down Expand Up @@ -262,7 +262,7 @@ func (rw *Worker) RunTxTaskNoLock(txTask *state.TxTask, isMining bool) {
}
}
default:
rw.taskGasPool.Reset(txTask.Tx.GetGas(), rw.chainConfig.GetMaxBlobGasPerBlock())
rw.taskGasPool.Reset(txTask.Tx.GetGas(), rw.chainConfig.GetMaxBlobGasPerBlock(header.Time))
rw.callTracer.Reset()
rw.vmCfg.SkipAnalysis = txTask.SkipAnalysis
ibs.SetTxContext(txTask.TxIndex)
Expand Down
2 changes: 1 addition & 1 deletion consensus/merge/merge.go
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ func (s *Merge) verifyHeader(chain consensus.ChainHeaderReader, header, parent *
if err := misc.VerifyPresenceOfCancunHeaderFields(header); err != nil {
return err
}
expectedExcessBlobGas := misc.CalcExcessBlobGas(chain.Config(), parent)
expectedExcessBlobGas := misc.CalcExcessBlobGas(chain.Config(), parent, header.Time)
if *header.ExcessBlobGas != expectedExcessBlobGas {
return fmt.Errorf("invalid excessBlobGas: have %d, want %d", *header.ExcessBlobGas, expectedExcessBlobGas)
}
Expand Down
9 changes: 7 additions & 2 deletions consensus/misc/eip1559.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,13 @@ func (f eip1559Calculator) CurrentFees(chainConfig *chain.Config, db kv.Getter)
}

if currentHeader.ExcessBlobGas != nil {
excessBlobGas := CalcExcessBlobGas(chainConfig, currentHeader)
b, err := GetBlobGasPrice(chainConfig, excessBlobGas)
var nextHeaderTime = currentHeader.Time + 1 // Speculative - Next header must be at least 1 second ahead
parentHeader := rawdb.ReadHeaderByNumber(db, currentHeader.Number.Uint64()-1)
if parentHeader != nil {
nextHeaderTime = currentHeader.Time + (currentHeader.Time - parentHeader.Time) // This difference should be close enough to seconds per slot
}
excessBlobGas := CalcExcessBlobGas(chainConfig, currentHeader, nextHeaderTime)
b, err := GetBlobGasPrice(chainConfig, excessBlobGas, nextHeaderTime)
if err != nil {
return 0, 0, 0, 0, err
}
Expand Down
11 changes: 6 additions & 5 deletions consensus/misc/eip4844.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ import (
)

// CalcExcessBlobGas implements calc_excess_blob_gas from EIP-4844
func CalcExcessBlobGas(config *chain.Config, parent *types.Header) uint64 {
// Updated for EIP-7691: currentHeaderTime is used to determine the fork, and hence params
func CalcExcessBlobGas(config *chain.Config, parent *types.Header, currentHeaderTime uint64) uint64 {
var excessBlobGas, blobGasUsed uint64
if parent.ExcessBlobGas != nil {
excessBlobGas = *parent.ExcessBlobGas
Expand All @@ -41,10 +42,10 @@ func CalcExcessBlobGas(config *chain.Config, parent *types.Header) uint64 {
blobGasUsed = *parent.BlobGasUsed
}

if excessBlobGas+blobGasUsed < config.GetTargetBlobGasPerBlock() {
if excessBlobGas+blobGasUsed < config.GetTargetBlobGasPerBlock(currentHeaderTime) {
return 0
}
return excessBlobGas + blobGasUsed - config.GetTargetBlobGasPerBlock()
return excessBlobGas + blobGasUsed - config.GetTargetBlobGasPerBlock(currentHeaderTime)
}

// FakeExponential approximates factor * e ** (num / denom) using a taylor expansion
Expand Down Expand Up @@ -103,8 +104,8 @@ func VerifyAbsenceOfCancunHeaderFields(header *types.Header) error {
return nil
}

func GetBlobGasPrice(config *chain.Config, excessBlobGas uint64) (*uint256.Int, error) {
return FakeExponential(uint256.NewInt(config.GetMinBlobGasPrice()), uint256.NewInt(config.GetBlobGasPriceUpdateFraction()), excessBlobGas)
func GetBlobGasPrice(config *chain.Config, excessBlobGas uint64, headerTime uint64) (*uint256.Int, error) {
return FakeExponential(uint256.NewInt(config.GetMinBlobGasPrice()), uint256.NewInt(config.GetBlobGasPriceUpdateFraction(headerTime)), excessBlobGas)
}

func GetBlobGasUsed(numBlobs int) uint64 {
Expand Down
2 changes: 1 addition & 1 deletion core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ func ExecuteBlockEphemerally(
usedGas := new(uint64)
usedBlobGas := new(uint64)
gp := new(GasPool)
gp.AddGas(block.GasLimit()).AddBlobGas(chainConfig.GetMaxBlobGasPerBlock())
gp.AddGas(block.GasLimit()).AddBlobGas(chainConfig.GetMaxBlobGasPerBlock(block.Time()))

// TODO: send the new tracer once we switch to the tracing.Hook
if err := InitializeBlockExecution(engine, chainReader, block.Header(), chainConfig, ibs, stateWriter, logger, nil); err != nil {
Expand Down
2 changes: 1 addition & 1 deletion core/chain_makers.go
Original file line number Diff line number Diff line change
Expand Up @@ -596,7 +596,7 @@ func MakeEmptyHeader(parent *types.Header, chainConfig *chain.Config, timestamp
}

if chainConfig.IsCancun(header.Time) {
excessBlobGas := misc.CalcExcessBlobGas(chainConfig, parent)
excessBlobGas := misc.CalcExcessBlobGas(chainConfig, parent, header.Time)
header.ExcessBlobGas = &excessBlobGas
header.BlobGasUsed = new(uint64)
}
Expand Down
2 changes: 1 addition & 1 deletion core/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ func NewEVMBlockContext(header *types.Header, blockHashFunc func(n uint64) libco
var blobBaseFee *uint256.Int
if header.ExcessBlobGas != nil {
var err error
blobBaseFee, err = misc.GetBlobGasPrice(config, *header.ExcessBlobGas)
blobBaseFee, err = misc.GetBlobGasPrice(config, *header.ExcessBlobGas, header.Time)
if err != nil {
panic(err)
}
Expand Down
49 changes: 38 additions & 11 deletions erigon-lib/chain/chain_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ type Config struct {
TargetBlobGasPerBlock *uint64 `json:"targetBlobGasPerBlock,omitempty"`
BlobGasPriceUpdateFraction *uint64 `json:"blobGasPriceUpdateFraction,omitempty"`

// EIP-7691
MaxBlobGasPerBlockPrague *uint64 `json:"maxBlobGasPerBlockPrague,omitempty"`
TargetBlobGasPerBlockPrague *uint64 `json:"targetBlobGasPerBlockPrague,omitempty"`
BlobGasPriceUpdateFractionPrague *uint64 `json:"blobGasPriceUpdateFractionPrague,omitempty"`

// (Optional) governance contract where EIP-1559 fees will be sent to, which otherwise would be burnt since the London fork.
// A key corresponds to the block number, starting from which the fees are sent to the address (map value).
// Starting from Prague, EIP-4844 fees might be collected as well:
Expand Down Expand Up @@ -264,29 +269,51 @@ func (c *Config) GetMinBlobGasPrice() uint64 {
return 1 // MIN_BLOB_GASPRICE (EIP-4844)
}

func (c *Config) GetMaxBlobGasPerBlock() uint64 {
if c != nil && c.MaxBlobGasPerBlock != nil {
return *c.MaxBlobGasPerBlock
func (c *Config) GetMaxBlobGasPerBlock(t uint64) uint64 {
if c != nil {
if c.IsPrague(t) {
if c.MaxBlobGasPerBlockPrague != nil {
return *c.MaxBlobGasPerBlockPrague
}
return 1179648 // EIP-7691
} else if c.MaxBlobGasPerBlock != nil {
return *c.MaxBlobGasPerBlock
}
}
return 786432 // MAX_BLOB_GAS_PER_BLOCK (EIP-4844)
}

func (c *Config) GetTargetBlobGasPerBlock() uint64 {
if c != nil && c.TargetBlobGasPerBlock != nil {
return *c.TargetBlobGasPerBlock
func (c *Config) GetTargetBlobGasPerBlock(t uint64) uint64 {
if c != nil {
if c.IsPrague(t) {
if c.TargetBlobGasPerBlockPrague != nil {
return *c.TargetBlobGasPerBlockPrague
}
return 786432
} else if c.TargetBlobGasPerBlock != nil {
return *c.TargetBlobGasPerBlock
}
}
return 393216 // TARGET_BLOB_GAS_PER_BLOCK (EIP-4844)
}

func (c *Config) GetBlobGasPriceUpdateFraction() uint64 {
if c != nil && c.BlobGasPriceUpdateFraction != nil {
return *c.BlobGasPriceUpdateFraction
func (c *Config) GetBlobGasPriceUpdateFraction(t uint64) uint64 {
if c != nil {
if c.IsPrague(t) {
if c.BlobGasPriceUpdateFractionPrague != nil {
return *c.BlobGasPriceUpdateFractionPrague
}
return 5007716

} else if c.BlobGasPriceUpdateFraction != nil {
return *c.BlobGasPriceUpdateFraction
}
}
return 3338477 // BLOB_GASPRICE_UPDATE_FRACTION (EIP-4844)
}

func (c *Config) GetMaxBlobsPerBlock() uint64 {
return c.GetMaxBlobGasPerBlock() / fixedgas.BlobGasPerBlob
func (c *Config) GetMaxBlobsPerBlock(time uint64) uint64 {
return c.GetMaxBlobGasPerBlock(time) / fixedgas.BlobGasPerBlob
}

// CheckCompatible checks whether scheduled fork transitions have been imported
Expand Down
2 changes: 1 addition & 1 deletion eth/ethutils/receipt.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ func MarshalReceipt(
if header.ExcessBlobGas == nil {
log.Warn("excess blob gas not set when trying to marshal blob tx")
} else {
blobGasPrice, err := misc.GetBlobGasPrice(chainConfig, *header.ExcessBlobGas)
blobGasPrice, err := misc.GetBlobGasPrice(chainConfig, *header.ExcessBlobGas, header.Time)
if err != nil {
log.Error(err.Error())
}
Expand Down
38 changes: 26 additions & 12 deletions eth/gasprice/feehistory.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ type blockFees struct {
blobBaseFee, nextBlobBaseFee *big.Int
gasUsedRatio float64
blobGasUsedRatio float64
secondsPerSlot uint64
err error
}

Expand Down Expand Up @@ -97,12 +98,12 @@ func (oracle *Oracle) processBlock(bf *blockFees, percentiles []float64) {

// Fill in blob base fee and next blob base fee.
if excessBlobGas := bf.header.ExcessBlobGas; excessBlobGas != nil {
blobBaseFee256, err := misc.GetBlobGasPrice(chainconfig, *excessBlobGas)
blobBaseFee256, err := misc.GetBlobGasPrice(chainconfig, *excessBlobGas, bf.header.Time)
if err != nil {
bf.err = err
return
}
nextBlobBaseFee256, err := misc.GetBlobGasPrice(chainconfig, misc.CalcExcessBlobGas(chainconfig, bf.header))
nextBlobBaseFee256, err := misc.GetBlobGasPrice(chainconfig, misc.CalcExcessBlobGas(chainconfig, bf.header, bf.header.Time+bf.secondsPerSlot), bf.header.Time+bf.secondsPerSlot)
if err != nil {
bf.err = err
return
Expand All @@ -116,8 +117,8 @@ func (oracle *Oracle) processBlock(bf *blockFees, percentiles []float64) {
}
bf.gasUsedRatio = float64(bf.header.GasUsed) / float64(bf.header.GasLimit)

if blobGasUsed := bf.header.BlobGasUsed; blobGasUsed != nil && chainconfig.GetMaxBlobGasPerBlock() != 0 {
bf.blobGasUsedRatio = float64(*blobGasUsed) / float64(chainconfig.GetMaxBlobGasPerBlock())
if blobGasUsed := bf.header.BlobGasUsed; blobGasUsed != nil && chainconfig.GetMaxBlobGasPerBlock(bf.header.Time) != 0 {
bf.blobGasUsedRatio = float64(*blobGasUsed) / float64(chainconfig.GetMaxBlobGasPerBlock(bf.header.Time))
}

if len(percentiles) == 0 {
Expand Down Expand Up @@ -168,38 +169,51 @@ func (oracle *Oracle) processBlock(bf *blockFees, percentiles []float64) {
// also returned if requested and available.
// Note: an error is only returned if retrieving the head header has failed. If there are no
// retrievable blocks in the specified range then zero block count is returned with no error.
func (oracle *Oracle) resolveBlockRange(ctx context.Context, lastBlock rpc.BlockNumber, blocks, maxHistory int) (*types.Block, []*types.Receipt, uint64, int, error) {
func (oracle *Oracle) resolveBlockRange(ctx context.Context, lastBlock rpc.BlockNumber, blocks, maxHistory int) (*types.Block, []*types.Receipt, uint64, int, uint64, error) {
var (
headBlock rpc.BlockNumber
pendingBlock *types.Block
pendingReceipts types.Receipts
secondsPerSlot uint64 // Time diff from parent block as an approx
lastBlockTime uint64
)
// query either pending block or head header and set headBlock
if lastBlock == rpc.PendingBlockNumber {
if pendingBlock, pendingReceipts = oracle.backend.PendingBlockAndReceipts(); pendingBlock != nil {
lastBlock = rpc.BlockNumber(pendingBlock.NumberU64())
headBlock = lastBlock - 1
lastBlockTime = pendingBlock.Time()
} else {
// pending block not supported by backend, process until latest block
lastBlock = rpc.LatestBlockNumber
blocks--
if blocks == 0 {
return nil, nil, 0, 0, nil
return nil, nil, 0, 0, 0, nil
}
}
}
if pendingBlock == nil {
// if pending block is not fetched then we retrieve the head header to get the head block number
if latestHeader, err := oracle.backend.HeaderByNumber(ctx, rpc.LatestBlockNumber); err == nil {
headBlock = rpc.BlockNumber(latestHeader.Number.Uint64())
lastBlockTime = latestHeader.Time
} else {
return nil, nil, 0, 0, err
return nil, nil, 0, 0, 0, err
}
}
if lastBlock == rpc.LatestBlockNumber {
lastBlock = headBlock
} else if pendingBlock == nil && lastBlock > headBlock {
return nil, nil, 0, 0, fmt.Errorf("%w: requested %d, head %d", ErrRequestBeyondHead, lastBlock, headBlock)
return nil, nil, 0, 0, 0, fmt.Errorf("%w: requested %d, head %d", ErrRequestBeyondHead, lastBlock, headBlock)
}
if lastBlock > 0 {
parentHeader, err := oracle.backend.HeaderByNumber(ctx, lastBlock-1)
if err != nil {
return nil, nil, 0, 0, 0, err
}
if parentHeader != nil {
secondsPerSlot = parentHeader.Time - lastBlockTime
}
}
if maxHistory != 0 {
// limit retrieval to the given number of latest blocks
Expand All @@ -208,15 +222,15 @@ func (oracle *Oracle) resolveBlockRange(ctx context.Context, lastBlock rpc.Block
if int64(blocks) > tooOldCount {
blocks -= int(tooOldCount)
} else {
return nil, nil, 0, 0, nil
return nil, nil, 0, 0, 0, nil
}
}
}
// ensure not trying to retrieve before genesis
if rpc.BlockNumber(blocks) > lastBlock+1 {
blocks = int(lastBlock + 1)
}
return pendingBlock, pendingReceipts, uint64(lastBlock), blocks, nil
return pendingBlock, pendingReceipts, uint64(lastBlock), blocks, secondsPerSlot, nil
}

// FeeHistory returns data relevant for fee estimation based on the specified range of blocks.
Expand Down Expand Up @@ -262,7 +276,7 @@ func (oracle *Oracle) FeeHistory(ctx context.Context, blocks int, unresolvedLast
pendingReceipts []*types.Receipt
err error
)
pendingBlock, pendingReceipts, lastBlock, blocks, err := oracle.resolveBlockRange(ctx, unresolvedLastBlock, blocks, maxHistory)
pendingBlock, pendingReceipts, lastBlock, blocks, secondsPerSlot, err := oracle.resolveBlockRange(ctx, unresolvedLastBlock, blocks, maxHistory)
if err != nil || blocks == 0 {
return libcommon.Big0, nil, nil, nil, nil, nil, err
}
Expand All @@ -289,7 +303,7 @@ func (oracle *Oracle) FeeHistory(ctx context.Context, blocks int, unresolvedLast
continue
}

fees := &blockFees{blockNumber: blockNumber}
fees := &blockFees{blockNumber: blockNumber, secondsPerSlot: secondsPerSlot}
if pendingBlock != nil && blockNumber >= pendingBlock.NumberU64() {
fees.block, fees.receipts = pendingBlock, pendingReceipts
} else {
Expand Down
4 changes: 2 additions & 2 deletions eth/stagedsync/stage_mining_exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ func getNextTransactions(
remainingGas := header.GasLimit - header.GasUsed
remainingBlobGas := uint64(0)
if header.BlobGasUsed != nil {
remainingBlobGas = cfg.chainConfig.GetMaxBlobGasPerBlock() - *header.BlobGasUsed
remainingBlobGas = cfg.chainConfig.GetMaxBlobGasPerBlock(header.Time) - *header.BlobGasUsed
}

provideOpts := []txnprovider.ProvideOption{
Expand Down Expand Up @@ -448,7 +448,7 @@ func addTransactionsToMiningBlock(
txnIdx := ibs.TxnIndex() + 1
gasPool := new(core.GasPool).AddGas(header.GasLimit - header.GasUsed)
if header.BlobGasUsed != nil {
gasPool.AddBlobGas(chainConfig.GetMaxBlobGasPerBlock() - *header.BlobGasUsed)
gasPool.AddBlobGas(chainConfig.GetMaxBlobGasPerBlock(header.Time) - *header.BlobGasUsed)
}
signer := types.MakeSigner(&chainConfig, header.Number.Uint64(), header.Time)

Expand Down
4 changes: 2 additions & 2 deletions tests/state_test_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ func (t *StateTest) RunNoVerify(tx kv.RwTx, subtest StateSubtest, vmconfig vm.Co
context.Difficulty = big.NewInt(0)
}
if config.IsCancun(block.Time()) && t.json.Env.ExcessBlobGas != nil {
context.BlobBaseFee, err = misc.GetBlobGasPrice(config, *t.json.Env.ExcessBlobGas)
context.BlobBaseFee, err = misc.GetBlobGasPrice(config, *t.json.Env.ExcessBlobGas, header.Time)
if err != nil {
return nil, libcommon.Hash{}, err
}
Expand All @@ -269,7 +269,7 @@ func (t *StateTest) RunNoVerify(tx kv.RwTx, subtest StateSubtest, vmconfig vm.Co
// Execute the message.
snapshot := statedb.Snapshot()
gaspool := new(core.GasPool)
gaspool.AddGas(block.GasLimit()).AddBlobGas(config.GetMaxBlobGasPerBlock())
gaspool.AddGas(block.GasLimit()).AddBlobGas(config.GetMaxBlobGasPerBlock(header.Time))
if _, err = core.ApplyMessage(evm, msg, gaspool, true /* refunds */, false /* gasBailout */); err != nil {
statedb.RevertToSnapshot(snapshot)
}
Expand Down
2 changes: 1 addition & 1 deletion turbo/engineapi/engine_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ func (s *EngineServer) newPayload(ctx context.Context, req *engine_types.Executi
}

if version >= clparams.DenebVersion {
err := ethutils.ValidateBlobs(req.BlobGasUsed.Uint64(), s.config.GetMaxBlobGasPerBlock(), s.config.GetMaxBlobsPerBlock(), expectedBlobHashes, &transactions)
err := ethutils.ValidateBlobs(req.BlobGasUsed.Uint64(), s.config.GetMaxBlobGasPerBlock(header.Time), s.config.GetMaxBlobsPerBlock(header.Time), expectedBlobHashes, &transactions)
if errors.Is(err, ethutils.ErrNilBlobHashes) {
return nil, &rpc.InvalidParamsError{Message: "nil blob hashes array"}
}
Expand Down
Loading
Loading