Skip to content

Commit

Permalink
Implement EIP-7691 blob gas price changes for pdn-5 (#13426)
Browse files Browse the repository at this point in the history
See ethereum/EIPs#9060

Tasks board - #12401
  • Loading branch information
somnathb1 authored Jan 16, 2025
1 parent abcd9d2 commit a715eea
Show file tree
Hide file tree
Showing 24 changed files with 139 additions and 88 deletions.
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 @@ -101,7 +101,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 @@ -263,7 +263,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 @@ -308,7 +308,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 @@ -273,7 +273,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

0 comments on commit a715eea

Please sign in to comment.