From a715eeaf5874f8254471c2361bff5c96d69d0648 Mon Sep 17 00:00:00 2001 From: Somnath Date: Thu, 16 Jan 2025 19:40:50 +0400 Subject: [PATCH] Implement EIP-7691 blob gas price changes for pdn-5 (#13426) See https://github.com/ethereum/EIPs/pull/9060 Tasks board - https://github.com/erigontech/erigon/issues/12401 --- accounts/abi/bind/backends/simulated.go | 2 +- .../services/polygon/proofgenerator_test.go | 2 +- cmd/state/commands/opcode_tracer.go | 2 +- cmd/state/exec3/state.go | 4 +- consensus/merge/merge.go | 2 +- consensus/misc/eip1559.go | 9 +++- consensus/misc/eip4844.go | 11 +++-- core/blockchain.go | 2 +- core/chain_makers.go | 2 +- core/evm.go | 2 +- erigon-lib/chain/chain_config.go | 49 ++++++++++++++----- eth/ethutils/receipt.go | 2 +- eth/gasprice/feehistory.go | 38 +++++++++----- eth/stagedsync/stage_mining_exec.go | 4 +- tests/state_test_util.go | 4 +- turbo/engineapi/engine_server.go | 2 +- turbo/execution/eth1/inserters.go | 23 --------- turbo/jsonrpc/eth_system.go | 7 ++- turbo/jsonrpc/receipts/receipts_generator.go | 2 +- turbo/stages/stageloop.go | 9 +++- txnprovider/txpool/assemble.go | 5 +- txnprovider/txpool/pool.go | 16 +++++- txnprovider/txpool/pool_fuzz_test.go | 4 +- txnprovider/txpool/pool_test.go | 24 ++++----- 24 files changed, 139 insertions(+), 88 deletions(-) diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index bada5001cb0..4d53c98a3b1 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -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() } diff --git a/cmd/devnet/services/polygon/proofgenerator_test.go b/cmd/devnet/services/polygon/proofgenerator_test.go index 93f9ffb8748..aad808047f5 100644 --- a/cmd/devnet/services/polygon/proofgenerator_test.go +++ b/cmd/devnet/services/polygon/proofgenerator_test.go @@ -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() diff --git a/cmd/state/commands/opcode_tracer.go b/cmd/state/commands/opcode_tracer.go index d0e7319f40c..a5ab6d83695 100644 --- a/cmd/state/commands/opcode_tracer.go +++ b/cmd/state/commands/opcode_tracer.go @@ -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 diff --git a/cmd/state/exec3/state.go b/cmd/state/exec3/state.go index 55ffd467274..852897ffa41 100644 --- a/cmd/state/exec3/state.go +++ b/cmd/state/exec3/state.go @@ -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 @@ -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) diff --git a/consensus/merge/merge.go b/consensus/merge/merge.go index aa71be6c447..bab6541532b 100644 --- a/consensus/merge/merge.go +++ b/consensus/merge/merge.go @@ -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) } diff --git a/consensus/misc/eip1559.go b/consensus/misc/eip1559.go index 1d56a708e2d..735ac1abede 100644 --- a/consensus/misc/eip1559.go +++ b/consensus/misc/eip1559.go @@ -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 } diff --git a/consensus/misc/eip4844.go b/consensus/misc/eip4844.go index f4db487e198..ca8c54790eb 100644 --- a/consensus/misc/eip4844.go +++ b/consensus/misc/eip4844.go @@ -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 @@ -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 @@ -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 { diff --git a/core/blockchain.go b/core/blockchain.go index 20dfdbc9496..44fe8e0ac5a 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -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 { diff --git a/core/chain_makers.go b/core/chain_makers.go index 778ba06009f..f167f52d554 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -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) } diff --git a/core/evm.go b/core/evm.go index 2f6dc320a5d..7b0a1a47018 100644 --- a/core/evm.go +++ b/core/evm.go @@ -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) } diff --git a/erigon-lib/chain/chain_config.go b/erigon-lib/chain/chain_config.go index f9073cd85f2..27f8b5803a8 100644 --- a/erigon-lib/chain/chain_config.go +++ b/erigon-lib/chain/chain_config.go @@ -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: @@ -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 diff --git a/eth/ethutils/receipt.go b/eth/ethutils/receipt.go index ce7925c6911..42c2c50dfd6 100644 --- a/eth/ethutils/receipt.go +++ b/eth/ethutils/receipt.go @@ -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()) } diff --git a/eth/gasprice/feehistory.go b/eth/gasprice/feehistory.go index 114bf931f39..b18ea28b717 100644 --- a/eth/gasprice/feehistory.go +++ b/eth/gasprice/feehistory.go @@ -61,6 +61,7 @@ type blockFees struct { blobBaseFee, nextBlobBaseFee *big.Int gasUsedRatio float64 blobGasUsedRatio float64 + secondsPerSlot uint64 err error } @@ -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 @@ -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 { @@ -168,23 +169,26 @@ 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 } } } @@ -192,14 +196,24 @@ func (oracle *Oracle) resolveBlockRange(ctx context.Context, lastBlock rpc.Block // 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 @@ -208,7 +222,7 @@ 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 } } } @@ -216,7 +230,7 @@ func (oracle *Oracle) resolveBlockRange(ctx context.Context, lastBlock rpc.Block 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. @@ -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 } @@ -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 { diff --git a/eth/stagedsync/stage_mining_exec.go b/eth/stagedsync/stage_mining_exec.go index 0315806c862..32f611c2f87 100644 --- a/eth/stagedsync/stage_mining_exec.go +++ b/eth/stagedsync/stage_mining_exec.go @@ -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{ @@ -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) diff --git a/tests/state_test_util.go b/tests/state_test_util.go index 2e16ac0c951..285db0ff9ee 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -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 } @@ -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) } diff --git a/turbo/engineapi/engine_server.go b/turbo/engineapi/engine_server.go index d33da9e6ba5..16d16e78f56 100644 --- a/turbo/engineapi/engine_server.go +++ b/turbo/engineapi/engine_server.go @@ -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"} } diff --git a/turbo/execution/eth1/inserters.go b/turbo/execution/eth1/inserters.go index 9d1cb1382f7..8efb536c5b2 100644 --- a/turbo/execution/eth1/inserters.go +++ b/turbo/execution/eth1/inserters.go @@ -20,37 +20,14 @@ import ( "context" "fmt" "math/big" - "reflect" - libcommon "github.com/erigontech/erigon-lib/common" "github.com/erigontech/erigon-lib/common/metrics" execution "github.com/erigontech/erigon-lib/gointerfaces/executionproto" "github.com/erigontech/erigon-lib/log/v3" "github.com/erigontech/erigon/core/rawdb" - "github.com/erigontech/erigon/core/types" - "github.com/erigontech/erigon/rpc" "github.com/erigontech/erigon/turbo/execution/eth1/eth1_utils" ) -func (e *EthereumExecutionModule) validatePayloadBlobs(expectedBlobHashes []libcommon.Hash, transactions []types.Transaction, blobGasUsed uint64) error { - if expectedBlobHashes == nil { - return &rpc.InvalidParamsError{Message: "nil blob hashes array"} - } - actualBlobHashes := []libcommon.Hash{} - for _, txn := range transactions { - actualBlobHashes = append(actualBlobHashes, txn.GetBlobHashes()...) - } - if len(actualBlobHashes) > int(e.config.GetMaxBlobsPerBlock()) || blobGasUsed > e.config.GetMaxBlobGasPerBlock() { - return nil - } - if !reflect.DeepEqual(actualBlobHashes, expectedBlobHashes) { - e.logger.Warn("[NewPayload] mismatch in blob hashes", - "expectedBlobHashes", expectedBlobHashes, "actualBlobHashes", actualBlobHashes) - return nil - } - return nil -} - func (e *EthereumExecutionModule) InsertBlocks(ctx context.Context, req *execution.InsertBlocksRequest) (*execution.InsertionResult, error) { if !e.semaphore.TryAcquire(1) { e.logger.Trace("ethereumExecutionModule.InsertBlocks: ExecutionStatus_Busy") diff --git a/turbo/jsonrpc/eth_system.go b/turbo/jsonrpc/eth_system.go index 10f987a6be8..a52467a0747 100644 --- a/turbo/jsonrpc/eth_system.go +++ b/turbo/jsonrpc/eth_system.go @@ -215,7 +215,12 @@ func (api *APIImpl) BlobBaseFee(ctx context.Context) (*hexutil.Big, error) { if config == nil { return (*hexutil.Big)(common.Big0), nil } - ret256, err := misc.GetBlobGasPrice(config, misc.CalcExcessBlobGas(config, header)) + nextBlockTime := header.Time + 1 // At least 1 second ahead + parent := rawdb.ReadHeaderByNumber(tx, header.Number.Uint64()-1) + if parent != nil { + nextBlockTime = header.Time + (header.Time - parent.Time) // Close enough to seconds per slot + } + ret256, err := misc.GetBlobGasPrice(config, misc.CalcExcessBlobGas(config, header, nextBlockTime), nextBlockTime) if err != nil { return nil, err } diff --git a/turbo/jsonrpc/receipts/receipts_generator.go b/turbo/jsonrpc/receipts/receipts_generator.go index 08878274853..ba6c5225131 100644 --- a/turbo/jsonrpc/receipts/receipts_generator.go +++ b/turbo/jsonrpc/receipts/receipts_generator.go @@ -93,7 +93,7 @@ func (g *Generator) PrepareEnv(ctx context.Context, header *types.Header, cfg *c usedGas := new(uint64) usedBlobGas := new(uint64) - gp := new(core.GasPool).AddGas(header.GasLimit).AddBlobGas(cfg.GetMaxBlobGasPerBlock()) + gp := new(core.GasPool).AddGas(header.GasLimit).AddBlobGas(cfg.GetMaxBlobGasPerBlock(header.Time)) noopWriter := state.NewNoopWriter() diff --git a/turbo/stages/stageloop.go b/turbo/stages/stageloop.go index 3c3db298934..da260170720 100644 --- a/turbo/stages/stageloop.go +++ b/turbo/stages/stageloop.go @@ -483,8 +483,13 @@ func (h *Hook) sendNotifications(tx kv.Tx, finishStageBeforeSync uint64) error { pendingBaseFee := misc.CalcBaseFee(h.chainConfig, currentHeader) pendingBlobFee := h.chainConfig.GetMinBlobGasPrice() if currentHeader.ExcessBlobGas != nil { - excessBlobGas := misc.CalcExcessBlobGas(h.chainConfig, currentHeader) - f, err := misc.GetBlobGasPrice(h.chainConfig, excessBlobGas) + nextBlockTime := currentHeader.Time + 1 + parentHeader := rawdb.ReadHeaderByNumber(tx, currentHeader.Number.Uint64()) + if parentHeader != nil { + nextBlockTime = currentHeader.Time + (currentHeader.Time - parentHeader.Time) // Approximately next block time + } + excessBlobGas := misc.CalcExcessBlobGas(h.chainConfig, currentHeader, nextBlockTime) + f, err := misc.GetBlobGasPrice(h.chainConfig, excessBlobGas, nextBlockTime) if err != nil { return err } diff --git a/txnprovider/txpool/assemble.go b/txnprovider/txpool/assemble.go index 77332be8baf..afd3cffd492 100644 --- a/txnprovider/txpool/assemble.go +++ b/txnprovider/txpool/assemble.go @@ -19,6 +19,7 @@ package txpool import ( "context" "math/big" + "time" "github.com/c2h5oh/datasize" "github.com/holiman/uint256" @@ -55,7 +56,7 @@ func Assemble( } chainID, _ := uint256.FromBig(chainConfig.ChainID) - maxBlobsPerBlock := chainConfig.GetMaxBlobsPerBlock() + maxBlobsPerBlock := chainConfig.GetMaxBlobsPerBlock(uint64(time.Now().Second())) shanghaiTime := chainConfig.ShanghaiTime var agraBlock *big.Int @@ -67,6 +68,7 @@ func Assemble( if cfg.OverridePragueTime != nil { pragueTime = cfg.OverridePragueTime } + maxBlobsPerBlockPrague := chainConfig.MaxBlobGasPerBlockPrague newTxns := make(chan Announcements, 1024) newSlotsStreams := &NewSlotsStreams{} @@ -83,6 +85,7 @@ func Assemble( cancunTime, pragueTime, maxBlobsPerBlock, + maxBlobsPerBlockPrague, sentryClients, stateChangesClient, builderNotifyNewTxns, diff --git a/txnprovider/txpool/pool.go b/txnprovider/txpool/pool.go index 4cf2e94c90a..36180831df0 100644 --- a/txnprovider/txpool/pool.go +++ b/txnprovider/txpool/pool.go @@ -144,6 +144,7 @@ type TxPool struct { pragueTime *uint64 isPostPrague atomic.Bool maxBlobsPerBlock uint64 + maxBlobsPerBlockPrague *uint64 feeCalculator FeeCalculator p2pFetcher *Fetch p2pSender *Send @@ -170,6 +171,7 @@ func New( cancunTime *big.Int, pragueTime *big.Int, maxBlobsPerBlock uint64, + maxBlobsPerBlockPrague *uint64, sentryClients []sentryproto.SentryClient, stateChangesClient StateChangesClient, builderNotifyNewTxns func(), @@ -223,6 +225,7 @@ func New( minedBlobTxnsByBlock: map[uint64][]*metaTxn{}, minedBlobTxnsByHash: map[string]*metaTxn{}, maxBlobsPerBlock: maxBlobsPerBlock, + maxBlobsPerBlockPrague: maxBlobsPerBlockPrague, feeCalculator: options.feeCalculator, builderNotifyNewTxns: builderNotifyNewTxns, newSlotsStreams: newSlotsStreams, @@ -865,7 +868,7 @@ func (p *TxPool) validateTx(txn *TxnSlot, isLocal bool, stateCache kvcache.Cache if blobCount == 0 { return txpoolcfg.NoBlobs } - if blobCount > p.maxBlobsPerBlock { + if blobCount > p.GetMaxBlobsPerBlock() { return txpoolcfg.TooManyBlobs } equalNumber := len(txn.BlobHashes) == len(txn.Blobs) && @@ -1082,6 +1085,17 @@ func (p *TxPool) isPrague() bool { return isTimeBasedForkActivated(&p.isPostPrague, p.pragueTime) } +func (p *TxPool) GetMaxBlobsPerBlock() uint64 { + if p.isPrague() { + if p.maxBlobsPerBlockPrague != nil { + return *p.maxBlobsPerBlockPrague + } + return 9 // EIP-7691 default + } else { + return p.maxBlobsPerBlock + } +} + // Check that the serialized txn should not exceed a certain max size func (p *TxPool) ValidateSerializedTxn(serializedTxn []byte) error { const ( diff --git a/txnprovider/txpool/pool_fuzz_test.go b/txnprovider/txpool/pool_fuzz_test.go index 72ebf61c204..edd13ed4931 100644 --- a/txnprovider/txpool/pool_fuzz_test.go +++ b/txnprovider/txpool/pool_fuzz_test.go @@ -325,7 +325,7 @@ func FuzzOnNewBlocks(f *testing.F) { cfg := txpoolcfg.DefaultConfig sendersCache := kvcache.New(kvcache.DefaultCoherentConfig) - pool, err := New(ctx, ch, db, coreDB, cfg, sendersCache, *u256.N1, nil, nil, nil, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, nil, func() {}, nil, log.New(), WithFeeCalculator(nil)) + pool, err := New(ctx, ch, db, coreDB, cfg, sendersCache, *u256.N1, nil, nil, nil, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, nil, nil, func() {}, nil, log.New(), WithFeeCalculator(nil)) assert.NoError(err) err = pool.start(ctx) @@ -551,7 +551,7 @@ func FuzzOnNewBlocks(f *testing.F) { check(p2pReceived, TxnSlots{}, "after_flush") checkNotify(p2pReceived, TxnSlots{}, "after_flush") - p2, err := New(ctx, ch, db, coreDB, txpoolcfg.DefaultConfig, sendersCache, *u256.N1, nil, nil, nil, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, nil, func() {}, nil, log.New(), WithFeeCalculator(nil)) + p2, err := New(ctx, ch, db, coreDB, txpoolcfg.DefaultConfig, sendersCache, *u256.N1, nil, nil, nil, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, nil, nil, func() {}, nil, log.New(), WithFeeCalculator(nil)) assert.NoError(err) p2.senders = pool.senders // senders are not persisted diff --git a/txnprovider/txpool/pool_test.go b/txnprovider/txpool/pool_test.go index c3960babbe7..f8c1be071e3 100644 --- a/txnprovider/txpool/pool_test.go +++ b/txnprovider/txpool/pool_test.go @@ -59,7 +59,7 @@ func TestNonceFromAddress(t *testing.T) { db := memdb.NewTestPoolDB(t) cfg := txpoolcfg.DefaultConfig sendersCache := kvcache.New(kvcache.DefaultCoherentConfig) - pool, err := New(ctx, ch, db, coreDB, cfg, sendersCache, *u256.N1, nil, nil, nil, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, nil, func() {}, nil, log.New(), WithFeeCalculator(nil)) + pool, err := New(ctx, ch, db, coreDB, cfg, sendersCache, *u256.N1, nil, nil, nil, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, nil, nil, func() {}, nil, log.New(), WithFeeCalculator(nil)) assert.NoError(err) require.True(pool != nil) var stateVersionID uint64 = 0 @@ -179,7 +179,7 @@ func TestMultipleAuthorizations(t *testing.T) { cfg := txpoolcfg.DefaultConfig sendersCache := kvcache.New(kvcache.DefaultCoherentConfig) - pool, err := New(ctx, ch, db, coreDB, cfg, sendersCache, *u256.N1, common.Big0 /* shanghaiTime */, nil /* agraBlock */, common.Big0 /* cancunTime */, common.Big0 /* pragueTime */, fixedgas.DefaultMaxBlobsPerBlock, nil, nil, func() {}, nil, log.New(), WithFeeCalculator(nil)) + pool, err := New(ctx, ch, db, coreDB, cfg, sendersCache, *u256.N1, common.Big0 /* shanghaiTime */, nil /* agraBlock */, common.Big0 /* cancunTime */, common.Big0 /* pragueTime */, fixedgas.DefaultMaxBlobsPerBlock, nil, nil, nil, func() {}, nil, log.New(), WithFeeCalculator(nil)) assert.NoError(t, err) require.True(t, pool != nil) @@ -431,7 +431,7 @@ func TestReplaceWithHigherFee(t *testing.T) { t.Cleanup(cancel) cfg := txpoolcfg.DefaultConfig sendersCache := kvcache.New(kvcache.DefaultCoherentConfig) - pool, err := New(ctx, ch, db, coreDB, cfg, sendersCache, *u256.N1, nil, nil, nil, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, nil, func() {}, nil, log.New(), WithFeeCalculator(nil)) + pool, err := New(ctx, ch, db, coreDB, cfg, sendersCache, *u256.N1, nil, nil, nil, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, nil, nil, func() {}, nil, log.New(), WithFeeCalculator(nil)) assert.NoError(err) require.NotEqual(nil, pool) var stateVersionID uint64 = 0 @@ -548,7 +548,7 @@ func TestReverseNonces(t *testing.T) { t.Cleanup(cancel) cfg := txpoolcfg.DefaultConfig sendersCache := kvcache.New(kvcache.DefaultCoherentConfig) - pool, err := New(ctx, ch, db, coreDB, cfg, sendersCache, *u256.N1, nil, nil, nil, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, nil, func() {}, nil, log.New(), WithFeeCalculator(nil)) + pool, err := New(ctx, ch, db, coreDB, cfg, sendersCache, *u256.N1, nil, nil, nil, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, nil, nil, func() {}, nil, log.New(), WithFeeCalculator(nil)) assert.NoError(err) require.True(pool != nil) var stateVersionID uint64 = 0 @@ -672,7 +672,7 @@ func TestTxnPoke(t *testing.T) { t.Cleanup(cancel) cfg := txpoolcfg.DefaultConfig sendersCache := kvcache.New(kvcache.DefaultCoherentConfig) - pool, err := New(ctx, ch, db, coreDB, cfg, sendersCache, *u256.N1, nil, nil, nil, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, nil, func() {}, nil, log.New(), WithFeeCalculator(nil)) + pool, err := New(ctx, ch, db, coreDB, cfg, sendersCache, *u256.N1, nil, nil, nil, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, nil, nil, func() {}, nil, log.New(), WithFeeCalculator(nil)) assert.NoError(err) require.True(pool != nil) var stateVersionID uint64 = 0 @@ -897,7 +897,7 @@ func TestShanghaiValidateTxn(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) t.Cleanup(cancel) cache := &kvcache.DummyCache{} - pool, err := New(ctx, ch, nil, coreDB, cfg, cache, *u256.N1, shanghaiTime, nil /* agraBlock */, nil /* cancunTime */, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, nil, func() {}, nil, logger, WithFeeCalculator(nil)) + pool, err := New(ctx, ch, nil, coreDB, cfg, cache, *u256.N1, shanghaiTime, nil /* agraBlock */, nil /* cancunTime */, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, nil, nil, func() {}, nil, logger, WithFeeCalculator(nil)) asrt.NoError(err) tx, err := coreDB.BeginRw(ctx) defer tx.Rollback() @@ -944,7 +944,7 @@ func TestTooHighGasLimitTxnValidation(t *testing.T) { t.Cleanup(cancel) cfg := txpoolcfg.DefaultConfig sendersCache := kvcache.New(kvcache.DefaultCoherentConfig) - pool, err := New(ctx, ch, db, coreDB, cfg, sendersCache, *u256.N1, nil, nil, nil, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, nil, func() {}, nil, log.New(), WithFeeCalculator(nil)) + pool, err := New(ctx, ch, db, coreDB, cfg, sendersCache, *u256.N1, nil, nil, nil, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, nil, nil, func() {}, nil, log.New(), WithFeeCalculator(nil)) assert.NoError(err) require.True(pool != nil) var stateVersionID uint64 = 0 @@ -1004,7 +1004,7 @@ func TestSetCodeTxnValidationWithLargeAuthorizationValues(t *testing.T) { cache := &kvcache.DummyCache{} logger := log.New() pool, err := New(ctx, ch, nil, coreDB, cfg, cache, chainID, common.Big0 /* shanghaiTime */, nil, /* agraBlock */ - common.Big0 /* cancunTime */, common.Big0 /* pragueTime */, fixedgas.DefaultMaxBlobsPerBlock, nil, nil, func() {}, nil, logger, WithFeeCalculator(nil)) + common.Big0 /* cancunTime */, common.Big0 /* pragueTime */, fixedgas.DefaultMaxBlobsPerBlock, nil, nil, nil, func() {}, nil, logger, WithFeeCalculator(nil)) assert.NoError(t, err) pool.blockGasLimit.Store(30_000_000) tx, err := coreDB.BeginRw(ctx) @@ -1052,7 +1052,7 @@ func TestBlobTxnReplacement(t *testing.T) { t.Cleanup(cancel) cfg := txpoolcfg.DefaultConfig sendersCache := kvcache.New(kvcache.DefaultCoherentConfig) - pool, err := New(ctx, ch, db, coreDB, cfg, sendersCache, *u256.N1, common.Big0, nil, common.Big0, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, nil, func() {}, nil, log.New(), WithFeeCalculator(nil)) + pool, err := New(ctx, ch, db, coreDB, cfg, sendersCache, *u256.N1, common.Big0, nil, common.Big0, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, nil, nil, func() {}, nil, log.New(), WithFeeCalculator(nil)) assert.NoError(err) require.True(pool != nil) @@ -1230,7 +1230,7 @@ func TestDropRemoteAtNoGossip(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) t.Cleanup(cancel) - txnPool, err := New(ctx, ch, db, coreDB, cfg, sendersCache, *u256.N1, big.NewInt(0), big.NewInt(0), nil, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, nil, func() {}, nil, logger, WithFeeCalculator(nil)) + txnPool, err := New(ctx, ch, db, coreDB, cfg, sendersCache, *u256.N1, big.NewInt(0), big.NewInt(0), nil, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, nil, nil, func() {}, nil, logger, WithFeeCalculator(nil)) assert.NoError(err) require.True(txnPool != nil) @@ -1335,7 +1335,7 @@ func TestBlobSlots(t *testing.T) { cfg.TotalBlobPoolLimit = 20 sendersCache := kvcache.New(kvcache.DefaultCoherentConfig) - pool, err := New(ctx, ch, db, coreDB, cfg, sendersCache, *u256.N1, common.Big0, nil, common.Big0, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, nil, func() {}, nil, log.New(), WithFeeCalculator(nil)) + pool, err := New(ctx, ch, db, coreDB, cfg, sendersCache, *u256.N1, common.Big0, nil, common.Big0, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, nil, nil, func() {}, nil, log.New(), WithFeeCalculator(nil)) assert.NoError(err) require.True(pool != nil) var stateVersionID uint64 = 0 @@ -1409,7 +1409,7 @@ func TestGasLimitChanged(t *testing.T) { db := memdb.NewTestPoolDB(t) cfg := txpoolcfg.DefaultConfig sendersCache := kvcache.New(kvcache.DefaultCoherentConfig) - pool, err := New(ctx, ch, db, coreDB, cfg, sendersCache, *u256.N1, nil, nil, nil, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, nil, func() {}, nil, log.New(), WithFeeCalculator(nil)) + pool, err := New(ctx, ch, db, coreDB, cfg, sendersCache, *u256.N1, nil, nil, nil, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, nil, nil, func() {}, nil, log.New(), WithFeeCalculator(nil)) assert.NoError(err) require.True(pool != nil) var stateVersionID uint64 = 0