diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index 171f5df8a81..9ab0840ba5f 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -174,7 +174,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() } @@ -721,7 +721,7 @@ func (b *SimulatedBackend) callContract(_ context.Context, call ethereum.CallMsg txContext := core.NewEVMTxContext(msg) header := block.Header() - evmContext := core.NewEVMBlockContext(header, core.GetHashFn(header, b.getHeader), b.m.Engine, nil) + evmContext := core.NewEVMBlockContext(header, core.GetHashFn(header, b.getHeader), b.m.Engine, nil, b.m.ChainConfig) // Create a new environment which holds all relevant information // about the transaction and calling mechanisms. vmEnv := vm.NewEVM(evmContext, txContext, statedb, b.m.ChainConfig, vm.Config{}) diff --git a/cmd/devnet/services/polygon/proofgenerator_test.go b/cmd/devnet/services/polygon/proofgenerator_test.go index 8880de213c0..cd94483ec1e 100644 --- a/cmd/devnet/services/polygon/proofgenerator_test.go +++ b/cmd/devnet/services/polygon/proofgenerator_test.go @@ -154,7 +154,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 26c2fd61deb..dd15180b4a2 100644 --- a/cmd/state/commands/opcode_tracer.go +++ b/cmd/state/commands/opcode_tracer.go @@ -711,7 +711,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 10edbc93423..037d60e00fb 100644 --- a/cmd/state/exec3/state.go +++ b/cmd/state/exec3/state.go @@ -194,7 +194,7 @@ func (rw *Worker) RunTxTaskNoLock(txTask *exec22.TxTask) { blockContext := txTask.EvmBlockContext if !rw.background { getHashFn := core.GetHashFn(header, rw.getHeader) - blockContext = core.NewEVMBlockContext(header, getHashFn, rw.engine, nil /* author */) + blockContext = core.NewEVMBlockContext(header, getHashFn, rw.engine, nil /* author */, rw.chainConfig) } rw.evm.ResetBetweenBlocks(blockContext, core.NewEVMTxContext(msg), ibs, vmConfig, rules) diff --git a/consensus/merge/merge.go b/consensus/merge/merge.go index 40f662c2524..44593172381 100644 --- a/consensus/merge/merge.go +++ b/consensus/merge/merge.go @@ -283,7 +283,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 697dfc7f770..34e6f10e7a4 100644 --- a/consensus/misc/eip1559.go +++ b/consensus/misc/eip1559.go @@ -84,10 +84,17 @@ 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 { blobFee = b.Uint64() + } else { + return 0, 0, 0, 0, err } } } diff --git a/consensus/misc/eip4844.go b/consensus/misc/eip4844.go index ca40c89d1dd..f35491435b4 100644 --- a/consensus/misc/eip4844.go +++ b/consensus/misc/eip4844.go @@ -28,7 +28,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 @@ -37,10 +38,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 @@ -99,8 +100,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 d55b9cdc98f..362a7ee7b0e 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -96,7 +96,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())) if err := InitializeBlockExecution(engine, chainReader, block.Header(), chainConfig, ibs, logger); err != nil { return nil, err @@ -265,7 +265,7 @@ func SysCallContract(contract libcommon.Address, data []byte, chainConfig *chain author = &state.SystemAddress txContext = NewEVMTxContext(msg) } - blockContext := NewEVMBlockContext(header, GetHashFn(header, nil), engine, author) + blockContext := NewEVMBlockContext(header, GetHashFn(header, nil), engine, author, chainConfig) evm := vm.NewEVM(blockContext, txContext, ibs, chainConfig, vmConfig) ret, _, err := evm.Call( @@ -299,7 +299,7 @@ func SysCreate(contract libcommon.Address, data []byte, chainConfig chain.Config // Create a new context to be used in the EVM environment author := &contract txContext := NewEVMTxContext(msg) - blockContext := NewEVMBlockContext(header, GetHashFn(header, nil), nil, author) + blockContext := NewEVMBlockContext(header, GetHashFn(header, nil), nil, author, &chainConfig) evm := vm.NewEVM(blockContext, txContext, ibs, &chainConfig, vmConfig) ret, _, err := evm.SysCreate( diff --git a/core/chain_makers.go b/core/chain_makers.go index 386b9cd4b7a..b6646afdecd 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -600,7 +600,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 7534cfc1e13..f20223fc1ff 100644 --- a/core/evm.go +++ b/core/evm.go @@ -1,18 +1,21 @@ // Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. +// (original work) +// Copyright 2024 The Erigon Authors +// (modifications) +// This file is part of Erigon. // -// The go-ethereum library is free software: you can redistribute it and/or modify +// Erigon is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // -// The go-ethereum library is distributed in the hope that it will be useful, +// Erigon is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . +// along with Erigon. If not, see . package core @@ -22,16 +25,19 @@ import ( "github.com/holiman/uint256" + "github.com/erigontech/erigon-lib/chain" libcommon "github.com/erigontech/erigon-lib/common" "github.com/erigontech/erigon/consensus" "github.com/erigontech/erigon/consensus/merge" + "github.com/erigontech/erigon/consensus/misc" "github.com/erigontech/erigon/core/types" "github.com/erigontech/erigon/core/vm/evmtypes" ) // NewEVMBlockContext creates a new context for use in the EVM. -func NewEVMBlockContext(header *types.Header, blockHashFunc func(n uint64) libcommon.Hash, engine consensus.EngineReader, author *libcommon.Address) evmtypes.BlockContext { +func NewEVMBlockContext(header *types.Header, blockHashFunc func(n uint64) libcommon.Hash, + engine consensus.EngineReader, author *libcommon.Address, config *chain.Config) evmtypes.BlockContext { // If we don't have an explicit author (i.e. not mining), extract from the header var beneficiary libcommon.Address if author == nil { @@ -54,10 +60,13 @@ func NewEVMBlockContext(header *types.Header, blockHashFunc func(n uint64) libco *prevRandDao = header.MixDigest } - var excessBlobGas *uint64 + var blobBaseFee *uint256.Int if header.ExcessBlobGas != nil { - excessBlobGas = new(uint64) - *excessBlobGas = *header.ExcessBlobGas + var err error + blobBaseFee, err = misc.GetBlobGasPrice(config, *header.ExcessBlobGas, header.Time) + if err != nil { + panic(err) + } } var transferFunc evmtypes.TransferFunc @@ -81,7 +90,7 @@ func NewEVMBlockContext(header *types.Header, blockHashFunc func(n uint64) libco BaseFee: &baseFee, GasLimit: header.GasLimit, PrevRanDao: prevRandDao, - ExcessBlobGas: excessBlobGas, + BlobBaseFee: blobBaseFee, } } diff --git a/core/state_processor.go b/core/state_processor.go index c65a7582ad3..ac393408a9d 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -112,7 +112,7 @@ func ApplyTransaction(config *chain.Config, blockHashFunc func(n uint64) libcomm // about the transaction and calling mechanisms. cfg.SkipAnalysis = SkipAnalysis(config, header.Number.Uint64()) - blockContext := NewEVMBlockContext(header, blockHashFunc, engine, author) + blockContext := NewEVMBlockContext(header, blockHashFunc, engine, author, config) vmenv := vm.NewEVM(blockContext, evmtypes.TxContext{}, ibs, config, cfg) return applyTransaction(config, engine, gp, ibs, stateWriter, header, tx, usedGas, usedBlobGas, vmenv, cfg) diff --git a/core/state_transition.go b/core/state_transition.go index 85ae1e53980..112229db8ec 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -32,7 +32,6 @@ import ( cmath "github.com/erigontech/erigon/common/math" "github.com/erigontech/erigon/common/u256" - "github.com/erigontech/erigon/consensus/misc" "github.com/erigontech/erigon/core/types" "github.com/erigontech/erigon/core/vm" "github.com/erigontech/erigon/core/vm/evmtypes" @@ -172,13 +171,10 @@ func (st *StateTransition) buyGas(gasBailout bool) error { // compute blob fee for eip-4844 data blobs if any blobGasVal := new(uint256.Int) if st.evm.ChainRules().IsCancun { - if st.evm.Context.ExcessBlobGas == nil { + blobGasPrice := st.evm.Context.BlobBaseFee + if blobGasPrice == nil { return fmt.Errorf("%w: Cancun is active but ExcessBlobGas is nil", ErrInternalFailure) } - blobGasPrice, err := misc.GetBlobGasPrice(st.evm.ChainConfig(), *st.evm.Context.ExcessBlobGas) - if err != nil { - return err - } blobGasVal, overflow = blobGasVal.MulOverflow(blobGasPrice, new(uint256.Int).SetUint64(st.msg.BlobGas())) if overflow { return fmt.Errorf("%w: overflow converting blob gas: %v", ErrInsufficientFunds, blobGasVal) @@ -211,7 +207,8 @@ func (st *StateTransition) buyGas(gasBailout bool) error { } } } - if have, want := st.state.GetBalance(st.msg.From()), balanceCheck; have.Cmp(want) < 0 { + balance := st.state.GetBalance(st.msg.From()) + if have, want := balance, balanceCheck; have.Cmp(want) < 0 { return fmt.Errorf("%w: address %v have %v want %v", ErrInsufficientFunds, st.msg.From().Hex(), have, want) } st.state.SubBalance(st.msg.From(), gasVal) @@ -280,18 +277,14 @@ func (st *StateTransition) preCheck(gasBailout bool) error { } } if st.msg.BlobGas() > 0 && st.evm.ChainRules().IsCancun { - if st.evm.Context.ExcessBlobGas == nil { + blobGasPrice := st.evm.Context.BlobBaseFee + if blobGasPrice == nil { return fmt.Errorf("%w: Cancun is active but ExcessBlobGas is nil", ErrInternalFailure) } - blobGasPrice, err := misc.GetBlobGasPrice(st.evm.ChainConfig(), *st.evm.Context.ExcessBlobGas) - if err != nil { - return err - } maxFeePerBlobGas := st.msg.MaxFeePerBlobGas() if !st.evm.Config().NoBaseFee && blobGasPrice.Cmp(maxFeePerBlobGas) > 0 { - return fmt.Errorf("%w: address %v, maxFeePerBlobGas: %v blobGasPrice: %v, excessBlobGas: %v", - ErrMaxFeePerBlobGas, - st.msg.From().Hex(), st.msg.MaxFeePerBlobGas(), blobGasPrice, st.evm.Context.ExcessBlobGas) + return fmt.Errorf("%w: address %v, maxFeePerBlobGas: %v < blobGasPrice: %v", + ErrMaxFeePerBlobGas, st.msg.From().Hex(), st.msg.MaxFeePerBlobGas(), blobGasPrice) } } diff --git a/core/vm/eips.go b/core/vm/eips.go index 0a84338aaa3..df16397d83c 100644 --- a/core/vm/eips.go +++ b/core/vm/eips.go @@ -24,7 +24,6 @@ import ( libcommon "github.com/erigontech/erigon-lib/common" - "github.com/erigontech/erigon/consensus/misc" "github.com/erigontech/erigon/params" ) @@ -303,11 +302,7 @@ func enable6780(jt *JumpTable) { // opBlobBaseFee implements the BLOBBASEFEE opcode func opBlobBaseFee(pc *uint64, interpreter *EVMInterpreter, callContext *ScopeContext) ([]byte, error) { - excessBlobGas := interpreter.evm.Context.ExcessBlobGas - blobBaseFee, err := misc.GetBlobGasPrice(interpreter.evm.ChainConfig(), *excessBlobGas) - if err != nil { - return nil, err - } + blobBaseFee := interpreter.evm.Context.BlobBaseFee callContext.Stack.Push(blobBaseFee) return nil, nil } diff --git a/core/vm/evmtypes/evmtypes.go b/core/vm/evmtypes/evmtypes.go index 121f08d8312..0c683c26e91 100644 --- a/core/vm/evmtypes/evmtypes.go +++ b/core/vm/evmtypes/evmtypes.go @@ -1,3 +1,19 @@ +// Copyright 2024 The Erigon Authors +// This file is part of Erigon. +// +// Erigon is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Erigon is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with Erigon. If not, see . + package evmtypes import ( @@ -25,15 +41,15 @@ type BlockContext struct { PostApplyMessage PostApplyMessageFunc // Block information - Coinbase common.Address // Provides information for COINBASE - GasLimit uint64 // Provides information for GASLIMIT - MaxGasLimit bool // Use GasLimit override for 2^256-1 (to be compatible with OpenEthereum's trace_call) - BlockNumber uint64 // Provides information for NUMBER - Time uint64 // Provides information for TIME - Difficulty *big.Int // Provides information for DIFFICULTY - BaseFee *uint256.Int // Provides information for BASEFEE - PrevRanDao *common.Hash // Provides information for PREVRANDAO - ExcessBlobGas *uint64 // Provides information for handling data blobs + Coinbase common.Address // Provides information for COINBASE + GasLimit uint64 // Provides information for GASLIMIT + MaxGasLimit bool // Use GasLimit override for 2^256-1 (to be compatible with OpenEthereum's trace_call) + BlockNumber uint64 // Provides information for NUMBER + Time uint64 // Provides information for TIME + Difficulty *big.Int // Provides information for DIFFICULTY + BaseFee *uint256.Int // Provides information for BASEFEE + PrevRanDao *common.Hash // Provides information for PREVRANDAO + BlobBaseFee *uint256.Int // Provides information for BLOBBASEFEE } // TxContext provides the EVM with information about a transaction. diff --git a/erigon-lib/chain/chain_config.go b/erigon-lib/chain/chain_config.go index 7dc9bd7a914..da32e2aa38f 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: @@ -261,29 +266,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/erigon-lib/txpool/pool.go b/erigon-lib/txpool/pool.go index 065915c1624..a3bb37825ad 100644 --- a/erigon-lib/txpool/pool.go +++ b/erigon-lib/txpool/pool.go @@ -233,6 +233,7 @@ type TxPool struct { pragueTime *uint64 isPostPrague atomic.Bool maxBlobsPerBlock uint64 + maxBlobsPerBlockPrague *uint64 feeCalculator FeeCalculator logger log.Logger } @@ -243,6 +244,7 @@ type FeeCalculator interface { func New(newTxs chan types.Announcements, coreDB kv.RoDB, cfg txpoolcfg.Config, cache kvcache.Cache, chainID uint256.Int, shanghaiTime, agraBlock, cancunTime, pragueTime *big.Int, maxBlobsPerBlock uint64, + maxBlobsPerBlockPrague *uint64, feeCalculator FeeCalculator, logger log.Logger, ) (*TxPool, error) { localsHistory, err := simplelru.NewLRU[string, struct{}](10_000, nil) @@ -289,8 +291,11 @@ func New(newTxs chan types.Announcements, coreDB kv.RoDB, cfg txpoolcfg.Config, minedBlobTxsByBlock: map[uint64][]*metaTx{}, minedBlobTxsByHash: map[string]*metaTx{}, maxBlobsPerBlock: maxBlobsPerBlock, + maxBlobsPerBlockPrague: maxBlobsPerBlockPrague, feeCalculator: feeCalculator, - logger: logger, + // builderNotifyNewTxns: builderNotifyNewTxns, + // newSlotsStreams: newSlotsStreams, + logger: logger, } if shanghaiTime != nil { @@ -864,7 +869,7 @@ func (p *TxPool) validateTx(txn *types.TxSlot, isLocal bool, stateCache kvcache. if blobCount == 0 { return txpoolcfg.NoBlobs } - if blobCount > p.maxBlobsPerBlock { + if blobCount > p.GetMaxBlobsPerBlock() { return txpoolcfg.TooManyBlobs } equalNumber := len(txn.BlobHashes) == len(txn.Blobs) && @@ -1073,6 +1078,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/erigon-lib/txpool/pool_fuzz_test.go b/erigon-lib/txpool/pool_fuzz_test.go index a4b00577406..0e6c826c1db 100644 --- a/erigon-lib/txpool/pool_fuzz_test.go +++ b/erigon-lib/txpool/pool_fuzz_test.go @@ -314,7 +314,7 @@ func FuzzOnNewBlocks(f *testing.F) { cfg := txpoolcfg.DefaultConfig sendersCache := kvcache.New(kvcache.DefaultCoherentConfig) - pool, err := New(ch, coreDB, cfg, sendersCache, *u256.N1, nil, nil, nil, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, log.New()) + pool, err := New(ch, coreDB, cfg, sendersCache, *u256.N1, nil, nil, nil, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, nil, log.New()) assert.NoError(err) err = pool.Start(ctx, db) @@ -540,7 +540,7 @@ func FuzzOnNewBlocks(f *testing.F) { check(p2pReceived, types.TxSlots{}, "after_flush") checkNotify(p2pReceived, types.TxSlots{}, "after_flush") - p2, err := New(ch, coreDB, txpoolcfg.DefaultConfig, sendersCache, *u256.N1, nil, nil, nil, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, log.New()) + p2, err := New(ch, coreDB, txpoolcfg.DefaultConfig, sendersCache, *u256.N1, nil, nil, nil, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, nil, log.New()) assert.NoError(err) p2.senders = pool.senders // senders are not persisted diff --git a/erigon-lib/txpool/pool_test.go b/erigon-lib/txpool/pool_test.go index 70b707b52f3..88ce27218f2 100644 --- a/erigon-lib/txpool/pool_test.go +++ b/erigon-lib/txpool/pool_test.go @@ -53,7 +53,7 @@ func TestNonceFromAddress(t *testing.T) { cfg := txpoolcfg.DefaultConfig sendersCache := kvcache.New(kvcache.DefaultCoherentConfig) - pool, err := New(ch, coreDB, cfg, sendersCache, *u256.N1, nil, nil, nil, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, log.New()) + pool, err := New(ch, coreDB, cfg, sendersCache, *u256.N1, nil, nil, nil, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, nil, log.New()) assert.NoError(err) require.True(pool != nil) ctx := context.Background() @@ -173,7 +173,7 @@ func TestReplaceWithHigherFee(t *testing.T) { cfg := txpoolcfg.DefaultConfig sendersCache := kvcache.New(kvcache.DefaultCoherentConfig) - pool, err := New(ch, coreDB, cfg, sendersCache, *u256.N1, nil, nil, nil, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, log.New()) + pool, err := New(ch, coreDB, cfg, sendersCache, *u256.N1, nil, nil, nil, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, nil, log.New()) assert.NoError(err) require.NotEqual(nil, pool) ctx := context.Background() @@ -290,7 +290,7 @@ func TestReverseNonces(t *testing.T) { cfg := txpoolcfg.DefaultConfig sendersCache := kvcache.New(kvcache.DefaultCoherentConfig) - pool, err := New(ch, coreDB, cfg, sendersCache, *u256.N1, nil, nil, nil, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, log.New()) + pool, err := New(ch, coreDB, cfg, sendersCache, *u256.N1, nil, nil, nil, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, nil, log.New()) assert.NoError(err) require.True(pool != nil) ctx := context.Background() @@ -417,7 +417,7 @@ func TestTxPoke(t *testing.T) { cfg := txpoolcfg.DefaultConfig sendersCache := kvcache.New(kvcache.DefaultCoherentConfig) - pool, err := New(ch, coreDB, cfg, sendersCache, *u256.N1, nil, nil, nil, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, log.New()) + pool, err := New(ch, coreDB, cfg, sendersCache, *u256.N1, nil, nil, nil, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, nil, log.New()) assert.NoError(err) require.True(pool != nil) ctx := context.Background() @@ -706,7 +706,7 @@ func TestShanghaiValidateTx(t *testing.T) { } cache := &kvcache.DummyCache{} - pool, err := New(ch, coreDB, cfg, cache, *u256.N1, shanghaiTime, nil /* agraBlock */, nil /* cancunTime */, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, logger) + pool, err := New(ch, coreDB, cfg, cache, *u256.N1, shanghaiTime, nil /* agraBlock */, nil /* cancunTime */, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, nil, logger) asrt.NoError(err) ctx := context.Background() tx, err := coreDB.BeginRw(ctx) @@ -755,7 +755,7 @@ func TestSetCodeTxValidationWithLargeAuthorizationValues(t *testing.T) { cache := &kvcache.DummyCache{} logger := log.New() pool, err := New(ch, coreDB, cfg, cache, chainID, common.Big0 /* shanghaiTime */, nil, /* agraBlock */ - common.Big0 /* cancunTime */, common.Big0 /* pragueTime */, fixedgas.DefaultMaxBlobsPerBlock, nil, logger) + common.Big0 /* cancunTime */, common.Big0 /* pragueTime */, fixedgas.DefaultMaxBlobsPerBlock, nil, nil, logger) assert.NoError(t, err) ctx := context.Background() tx, err := coreDB.BeginRw(ctx) @@ -800,7 +800,7 @@ func TestBlobTxReplacement(t *testing.T) { db, coreDB := memdb.NewTestPoolDB(t), memdb.NewTestDB(t) cfg := txpoolcfg.DefaultConfig sendersCache := kvcache.New(kvcache.DefaultCoherentConfig) - pool, err := New(ch, coreDB, cfg, sendersCache, *u256.N1, common.Big0, nil, common.Big0, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, log.New()) + pool, err := New(ch, coreDB, cfg, sendersCache, *u256.N1, common.Big0, nil, common.Big0, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, nil, log.New()) assert.NoError(err) require.True(pool != nil) ctx := context.Background() @@ -1017,7 +1017,7 @@ func TestDropRemoteAtNoGossip(t *testing.T) { logger := log.New() sendersCache := kvcache.New(kvcache.DefaultCoherentConfig) - txPool, err := New(ch, coreDB, cfg, sendersCache, *u256.N1, big.NewInt(0), big.NewInt(0), nil, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, logger) + txPool, err := New(ch, coreDB, cfg, sendersCache, *u256.N1, big.NewInt(0), big.NewInt(0), nil, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, nil, logger) assert.NoError(err) require.True(txPool != nil) @@ -1123,7 +1123,7 @@ func TestBlobSlots(t *testing.T) { cfg.TotalBlobPoolLimit = 20 sendersCache := kvcache.New(kvcache.DefaultCoherentConfig) - pool, err := New(ch, coreDB, cfg, sendersCache, *u256.N1, common.Big0, nil, common.Big0, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, log.New()) + pool, err := New(ch, coreDB, cfg, sendersCache, *u256.N1, common.Big0, nil, common.Big0, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, nil, log.New()) assert.NoError(err) require.True(pool != nil) ctx := context.Background() @@ -1197,7 +1197,7 @@ func TestGasLimitChanged(t *testing.T) { cfg := txpoolcfg.DefaultConfig sendersCache := kvcache.New(kvcache.DefaultCoherentConfig) - pool, err := New(ch, coreDB, cfg, sendersCache, *u256.N1, nil, nil, nil, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, log.New()) + pool, err := New(ch, coreDB, cfg, sendersCache, *u256.N1, nil, nil, nil, nil, fixedgas.DefaultMaxBlobsPerBlock, nil, nil, log.New()) assert.NoError(err) require.True(pool != nil) ctx := context.Background() diff --git a/erigon-lib/txpool/txpoolutil/all_components.go b/erigon-lib/txpool/txpoolutil/all_components.go index f009b5876e0..84618e0f385 100644 --- a/erigon-lib/txpool/txpoolutil/all_components.go +++ b/erigon-lib/txpool/txpoolutil/all_components.go @@ -132,7 +132,7 @@ func AllComponents(ctx context.Context, cfg txpoolcfg.Config, cache kvcache.Cach } chainID, _ := uint256.FromBig(chainConfig.ChainID) - maxBlobsPerBlock := chainConfig.GetMaxBlobsPerBlock() + maxBlobsPerBlock := chainConfig.GetMaxBlobsPerBlock(uint64(time.Now().Second())) shanghaiTime := chainConfig.ShanghaiTime var agraBlock *big.Int @@ -146,7 +146,7 @@ func AllComponents(ctx context.Context, cfg txpoolcfg.Config, cache kvcache.Cach } txPool, err := txpool.New(newTxs, chainDB, cfg, cache, *chainID, shanghaiTime, agraBlock, cancunTime, pragueTime, - maxBlobsPerBlock, feeCalculator, logger) + maxBlobsPerBlock, &maxBlobsPerBlock, feeCalculator, logger) if err != nil { return nil, nil, nil, nil, nil, err } diff --git a/eth/ethutils/receipt.go b/eth/ethutils/receipt.go index 8e0725788d4..62825e02ec0 100644 --- a/eth/ethutils/receipt.go +++ b/eth/ethutils/receipt.go @@ -77,7 +77,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 38736be31cb..99bc2faa6c5 100644 --- a/eth/gasprice/feehistory.go +++ b/eth/gasprice/feehistory.go @@ -51,10 +51,13 @@ type blockFees struct { block *types.Block // only set if reward percentiles are requested receipts types.Receipts // filled by processBlock - reward []*big.Int - baseFee, nextBaseFee *big.Int - gasUsedRatio float64 - err error + reward []*big.Int + baseFee, nextBaseFee *big.Int + blobBaseFee, nextBlobBaseFee *big.Int + gasUsedRatio float64 + blobGasUsedRatio float64 + secondsPerSlot uint64 + err error } // txGasAndReward is sorted in ascending order based on reward @@ -87,7 +90,32 @@ func (oracle *Oracle) processBlock(bf *blockFees, percentiles []float64) { } else { bf.nextBaseFee = new(big.Int) } + + // Fill in blob base fee and next blob base fee. + if excessBlobGas := bf.header.ExcessBlobGas; excessBlobGas != nil { + 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, bf.header.Time+bf.secondsPerSlot), bf.header.Time+bf.secondsPerSlot) + if err != nil { + bf.err = err + return + } + bf.blobBaseFee = blobBaseFee256.ToBig() + bf.nextBlobBaseFee = nextBlobBaseFee256.ToBig() + + } else { + bf.blobBaseFee = new(big.Int) + bf.nextBlobBaseFee = new(big.Int) + } bf.gasUsedRatio = float64(bf.header.GasUsed) / float64(bf.header.GasLimit) + + 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 { // rewards were not requested, return null return @@ -135,23 +163,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 } } } @@ -159,14 +190,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 @@ -175,7 +216,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 } } } @@ -183,7 +224,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. @@ -226,7 +267,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, err } @@ -251,7 +292,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/exec3.go b/eth/stagedsync/exec3.go index c36ccbc463d..e8891ec7ca9 100644 --- a/eth/stagedsync/exec3.go +++ b/eth/stagedsync/exec3.go @@ -532,7 +532,7 @@ Loop: defer getHashFnMute.Unlock() return f(n) } - blockContext := core.NewEVMBlockContext(header, getHashFn, engine, nil /* author */) + blockContext := core.NewEVMBlockContext(header, getHashFn, engine, nil /* author */, chainConfig) if parallel { select { @@ -1059,7 +1059,7 @@ func reconstituteStep(last bool, defer getHashFnMute.Unlock() return f(n) } - blockContext := core.NewEVMBlockContext(header, getHashFn, engine, nil /* author */) + blockContext := core.NewEVMBlockContext(header, getHashFn, engine, nil /* author */, chainConfig) rules := chainConfig.Rules(bn, b.Time()) for txIndex := -1; txIndex <= len(txs); txIndex++ { diff --git a/eth/stagedsync/stage_mining_exec.go b/eth/stagedsync/stage_mining_exec.go index a04d9e88e1e..164cb6363bc 100644 --- a/eth/stagedsync/stage_mining_exec.go +++ b/eth/stagedsync/stage_mining_exec.go @@ -197,7 +197,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 } if _, count, err = cfg.txPool.YieldBest(amount, &txSlots, poolTx, executionAt, remainingGas, remainingBlobGas, alreadyYielded); err != nil { @@ -377,7 +377,7 @@ func addTransactionsToMiningBlock(logPrefix string, current *MiningBlock, chainC tcount := 0 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/eth/tracers/tracers_test.go b/eth/tracers/tracers_test.go index f930bca90c8..ece271bdb53 100644 --- a/eth/tracers/tracers_test.go +++ b/eth/tracers/tracers_test.go @@ -1,18 +1,21 @@ // Copyright 2017 The go-ethereum Authors -// This file is part of the go-ethereum library. +// (original work) +// Copyright 2025 The Erigon Authors +// (modifications) +// This file is part of Erigon. // -// The go-ethereum library is free software: you can redistribute it and/or modify +// Erigon is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // -// The go-ethereum library is distributed in the hope that it will be useful, +// Erigon is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . +// along with Erigon. If not, see . package tracers_test @@ -72,18 +75,17 @@ func TestPrestateTracerCreate2(t *testing.T) { Origin: origin, GasPrice: uint256.NewInt(1), } - excessBlobGas := uint64(50000) context := evmtypes.BlockContext{ - CanTransfer: core.CanTransfer, - Transfer: consensus.Transfer, - Coinbase: libcommon.Address{}, - BlockNumber: 8000000, - Time: 5, - Difficulty: big.NewInt(0x30000), - GasLimit: uint64(6000000), - ExcessBlobGas: &excessBlobGas, + CanTransfer: core.CanTransfer, + Transfer: consensus.Transfer, + Coinbase: libcommon.Address{}, + BlockNumber: 8000000, + Time: 5, + Difficulty: big.NewInt(0x30000), + GasLimit: uint64(6000000), + BaseFee: uint256.NewInt(0), + BlobBaseFee: uint256.NewInt(50000), } - context.BaseFee = uint256.NewInt(0) alloc := types.GenesisAlloc{} // The code pushes 'deadbeef' into memory, then the other params, and calls CREATE2, then returns diff --git a/tests/state_test_util.go b/tests/state_test_util.go index ed132b2dfb4..41d2f0d9f8f 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -235,7 +235,7 @@ func (t *StateTest) RunNoVerify(tx kv.RwTx, subtest StateSubtest, vmconfig vm.Co // Prepare the EVM. txContext := core.NewEVMTxContext(msg) header := block.Header() - context := core.NewEVMBlockContext(header, core.GetHashFn(header, nil), nil, &t.json.Env.Coinbase) + context := core.NewEVMBlockContext(header, core.GetHashFn(header, nil), nil, &t.json.Env.Coinbase, config) context.GetHash = vmTestBlockHash if baseFee != nil { context.BaseFee = new(uint256.Int) @@ -244,13 +244,14 @@ func (t *StateTest) RunNoVerify(tx kv.RwTx, subtest StateSubtest, vmconfig vm.Co if t.json.Env.Random != nil { rnd := libcommon.BigToHash(t.json.Env.Random) context.PrevRanDao = &rnd + context.Difficulty = big.NewInt(0) } evm := vm.NewEVM(context, txContext, statedb, config, vmconfig) // 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 eff517858d1..dcd4bc38e57 100644 --- a/turbo/engineapi/engine_server.go +++ b/turbo/engineapi/engine_server.go @@ -242,7 +242,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 d0751720220..1e1bfdf23cd 100644 --- a/turbo/execution/eth1/inserters.go +++ b/turbo/execution/eth1/inserters.go @@ -3,36 +3,14 @@ package eth1 import ( "context" "fmt" - "reflect" - libcommon "github.com/erigontech/erigon-lib/common" "github.com/erigontech/erigon-lib/common/metrics" "github.com/erigontech/erigon-lib/gointerfaces/execution" "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 (s *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(s.config.GetMaxBlobsPerBlock()) || blobGasUsed > s.config.GetMaxBlobGasPerBlock() { - return nil - } - if !reflect.DeepEqual(actualBlobHashes, expectedBlobHashes) { - s.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_block.go b/turbo/jsonrpc/eth_block.go index 9e3e6155f29..ba94c7104f8 100644 --- a/turbo/jsonrpc/eth_block.go +++ b/turbo/jsonrpc/eth_block.go @@ -122,7 +122,7 @@ func (api *APIImpl) CallBundle(ctx context.Context, txHashes []common.Hash, stat return nil, err } - blockCtx := transactions.NewEVMBlockContext(engine, header, stateBlockNumberOrHash.RequireCanonical, tx, api._blockReader) + blockCtx := transactions.NewEVMBlockContext(engine, header, stateBlockNumberOrHash.RequireCanonical, tx, api._blockReader, chainConfig) txCtx := core.NewEVMTxContext(firstMsg) // Get a new instance of the EVM evm := vm.NewEVM(blockCtx, txCtx, ibs, chainConfig, vm.Config{Debug: false}) diff --git a/turbo/jsonrpc/eth_call.go b/turbo/jsonrpc/eth_call.go index 70519119ee8..fdb1074ce30 100644 --- a/turbo/jsonrpc/eth_call.go +++ b/turbo/jsonrpc/eth_call.go @@ -549,7 +549,7 @@ func (api *APIImpl) CreateAccessList(ctx context.Context, args ethapi2.CallArgs, // Apply the transaction with the access list tracer tracer := logger.NewAccessListTracer(accessList, excl, state) config := vm.Config{Tracer: tracer, Debug: true, NoBaseFee: true} - blockCtx := transactions.NewEVMBlockContext(engine, header, bNrOrHash.RequireCanonical, tx, api._blockReader) + blockCtx := transactions.NewEVMBlockContext(engine, header, bNrOrHash.RequireCanonical, tx, api._blockReader, chainConfig) txCtx := core.NewEVMTxContext(msg) evm := vm.NewEVM(blockCtx, txCtx, state, chainConfig, config) diff --git a/turbo/jsonrpc/eth_callMany.go b/turbo/jsonrpc/eth_callMany.go index e2fc12af8b9..76f3d0cd75f 100644 --- a/turbo/jsonrpc/eth_callMany.go +++ b/turbo/jsonrpc/eth_callMany.go @@ -155,7 +155,7 @@ func (api *APIImpl) CallMany(ctx context.Context, bundles []Bundle, simulateCont return hash } - blockCtx = core.NewEVMBlockContext(header, getHash, api.engine(), nil /* author */) + blockCtx = core.NewEVMBlockContext(header, getHash, api.engine(), nil /* author */, chainConfig) // Get a new instance of the EVM evm = vm.NewEVM(blockCtx, txCtx, st, chainConfig, vm.Config{Debug: false}) diff --git a/turbo/jsonrpc/eth_receipts.go b/turbo/jsonrpc/eth_receipts.go index 75aae170cc8..45900794bf8 100644 --- a/turbo/jsonrpc/eth_receipts.go +++ b/turbo/jsonrpc/eth_receipts.go @@ -59,7 +59,7 @@ func (api *BaseAPI) getReceipts(ctx context.Context, tx kv.Tx, block *types.Bloc usedGas := new(uint64) usedBlobGas := new(uint64) - gp := new(core.GasPool).AddGas(block.GasLimit()).AddBlobGas(chainConfig.GetMaxBlobGasPerBlock()) + gp := new(core.GasPool).AddGas(block.GasLimit()).AddBlobGas(chainConfig.GetMaxBlobGasPerBlock(block.Time())) noopWriter := state.NewNoopWriter() @@ -528,7 +528,7 @@ func txnExecutor(tx kv.TemporalTx, chainConfig *chain.Config, engine consensus.E func (e *intraBlockExec) changeBlock(header *types.Header) { e.blockNum = header.Number.Uint64() - blockCtx := transactions.NewEVMBlockContext(e.engine, header, true /* requireCanonical */, e.tx, e.br) + blockCtx := transactions.NewEVMBlockContext(e.engine, header, true /* requireCanonical */, e.tx, e.br, e.chainConfig) e.blockCtx = &blockCtx e.blockHash = header.Hash() e.header = header diff --git a/turbo/jsonrpc/eth_system.go b/turbo/jsonrpc/eth_system.go index 2f333d4a1ca..06b1bb33b84 100644 --- a/turbo/jsonrpc/eth_system.go +++ b/turbo/jsonrpc/eth_system.go @@ -201,6 +201,7 @@ func (b *GasPriceOracleBackend) HeaderByNumber(ctx context.Context, number rpc.B } return header, nil } + func (b *GasPriceOracleBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) { return b.baseApi.blockByRPCNumber(ctx, number, b.tx) } diff --git a/turbo/jsonrpc/otterscan_generic_tracer.go b/turbo/jsonrpc/otterscan_generic_tracer.go index cd3da0100dd..1dbf1d51f30 100644 --- a/turbo/jsonrpc/otterscan_generic_tracer.go +++ b/turbo/jsonrpc/otterscan_generic_tracer.go @@ -94,7 +94,7 @@ func (api *OtterscanAPIImpl) genericTracer(dbtx kv.Tx, ctx context.Context, bloc msg, _ := tx.AsMessage(*signer, header.BaseFee, rules) - BlockContext := core.NewEVMBlockContext(header, core.GetHashFn(header, getHeader), engine, nil) + BlockContext := core.NewEVMBlockContext(header, core.GetHashFn(header, getHeader), engine, nil, chainConfig) TxContext := core.NewEVMTxContext(msg) vmenv := vm.NewEVM(BlockContext, TxContext, ibs, chainConfig, vm.Config{Debug: true, Tracer: tracer}) diff --git a/turbo/jsonrpc/otterscan_search_trace.go b/turbo/jsonrpc/otterscan_search_trace.go index 7a64301ae10..0e64201a2e1 100644 --- a/turbo/jsonrpc/otterscan_search_trace.go +++ b/turbo/jsonrpc/otterscan_search_trace.go @@ -94,7 +94,7 @@ func (api *OtterscanAPIImpl) traceBlock(dbtx kv.Tx, ctx context.Context, blockNu msg, _ := tx.AsMessage(*signer, header.BaseFee, rules) tracer := NewTouchTracer(searchAddr) - BlockContext := core.NewEVMBlockContext(header, core.GetHashFn(header, getHeader), engine, nil) + BlockContext := core.NewEVMBlockContext(header, core.GetHashFn(header, getHeader), engine, nil, chainConfig) TxContext := core.NewEVMTxContext(msg) vmenv := vm.NewEVM(BlockContext, TxContext, ibs, chainConfig, vm.Config{Debug: true, Tracer: tracer}) diff --git a/turbo/jsonrpc/overlay_api.go b/turbo/jsonrpc/overlay_api.go index ffbf16bdb82..fe2b0850cb7 100644 --- a/turbo/jsonrpc/overlay_api.go +++ b/turbo/jsonrpc/overlay_api.go @@ -414,7 +414,6 @@ func (api *OverlayAPIImpl) replayBlock(ctx context.Context, blockNum uint64, sta blockCtx evmtypes.BlockContext txCtx evmtypes.TxContext overrideBlockHash map[uint64]common.Hash - baseFee uint256.Int ) blockLogs := []*types.Log{} @@ -451,23 +450,7 @@ func (api *OverlayAPIImpl) replayBlock(ctx context.Context, blockNum uint64, sta return hash } - if parent.BaseFee != nil { - baseFee.SetFromBig(parent.BaseFee) - } - - var excessBlobGas uint64 = 0 - blockCtx = evmtypes.BlockContext{ - CanTransfer: core.CanTransfer, - Transfer: consensus.Transfer, - GetHash: getHash, - Coinbase: parent.Coinbase, - BlockNumber: parent.Number.Uint64(), - Time: parent.Time, - Difficulty: new(big.Int).Set(parent.Difficulty), - GasLimit: parent.GasLimit, - BaseFee: &baseFee, - ExcessBlobGas: &excessBlobGas, - } + blockCtx = core.NewEVMBlockContext(parent, getHash, api.engine(), nil, chainConfig) signer := types.MakeSigner(chainConfig, blockNum, blockCtx.Time) rules := chainConfig.Rules(blockNum, blockCtx.Time) diff --git a/turbo/jsonrpc/trace_adhoc.go b/turbo/jsonrpc/trace_adhoc.go index 5df91faf428..7b2adc8e83f 100644 --- a/turbo/jsonrpc/trace_adhoc.go +++ b/turbo/jsonrpc/trace_adhoc.go @@ -1001,7 +1001,7 @@ func (api *TraceAPIImpl) Call(ctx context.Context, args TraceCallParam, traceTyp return nil, err } - blockCtx := transactions.NewEVMBlockContext(engine, header, blockNrOrHash.RequireCanonical, tx, api._blockReader) + blockCtx := transactions.NewEVMBlockContext(engine, header, blockNrOrHash.RequireCanonical, tx, api._blockReader, chainConfig) txCtx := core.NewEVMTxContext(msg) blockCtx.GasLimit = math.MaxUint64 @@ -1239,7 +1239,7 @@ func (api *TraceAPIImpl) doCallMany(ctx context.Context, dbtx kv.Tx, stateReader vmConfig.Tracer = &ot } - blockCtx := transactions.NewEVMBlockContext(engine, header, parentNrOrHash.RequireCanonical, dbtx, api._blockReader) + blockCtx := transactions.NewEVMBlockContext(engine, header, parentNrOrHash.RequireCanonical, dbtx, api._blockReader, chainConfig) if useParent { blockCtx.GasLimit = math.MaxUint64 blockCtx.MaxGasLimit = true diff --git a/turbo/jsonrpc/trace_filtering.go b/turbo/jsonrpc/trace_filtering.go index 1736b0c0a97..0fca43cabd4 100644 --- a/turbo/jsonrpc/trace_filtering.go +++ b/turbo/jsonrpc/trace_filtering.go @@ -788,7 +788,7 @@ func (api *TraceAPIImpl) filterV3(ctx context.Context, dbtx kv.TemporalTx, fromB vmConfig.Tracer = &ot ibs := state.New(cachedReader) - blockCtx := transactions.NewEVMBlockContext(engine, lastHeader, true /* requireCanonical */, dbtx, api._blockReader) + blockCtx := transactions.NewEVMBlockContext(engine, lastHeader, true /* requireCanonical */, dbtx, api._blockReader, chainConfig) txCtx := core.NewEVMTxContext(msg) evm := vm.NewEVM(blockCtx, txCtx, ibs, chainConfig, vmConfig) diff --git a/turbo/jsonrpc/tracing.go b/turbo/jsonrpc/tracing.go index b5bcc4b7388..9d2dfcd5976 100644 --- a/turbo/jsonrpc/tracing.go +++ b/turbo/jsonrpc/tracing.go @@ -361,7 +361,7 @@ func (api *PrivateDebugAPIImpl) TraceCall(ctx context.Context, args ethapi.CallA return fmt.Errorf("convert args to msg: %v", err) } - blockCtx := transactions.NewEVMBlockContext(engine, header, blockNrOrHash.RequireCanonical, dbtx, api._blockReader) + blockCtx := transactions.NewEVMBlockContext(engine, header, blockNrOrHash.RequireCanonical, dbtx, api._blockReader, chainConfig) txCtx := core.NewEVMTxContext(msg) // Trace the transaction and return return transactions.TraceTx(ctx, msg, blockCtx, txCtx, ibs, config, chainConfig, stream, api.evmCallTimeout) @@ -472,7 +472,7 @@ func (api *PrivateDebugAPIImpl) TraceCallMany(ctx context.Context, bundles []Bun return hash } - blockCtx = core.NewEVMBlockContext(header, getHash, api.engine(), nil /* author */) + blockCtx = core.NewEVMBlockContext(header, getHash, api.engine(), nil /* author */, chainConfig) // Get a new instance of the EVM evm = vm.NewEVM(blockCtx, txCtx, st, chainConfig, vm.Config{Debug: false}) signer := types.MakeSigner(chainConfig, blockNum, block.Time()) diff --git a/turbo/stages/mock/mock_sentry.go b/turbo/stages/mock/mock_sentry.go index b7e5ec60f51..ac807c4b4c2 100644 --- a/turbo/stages/mock/mock_sentry.go +++ b/turbo/stages/mock/mock_sentry.go @@ -21,6 +21,7 @@ import ( "github.com/erigontech/erigon-lib/chain" libcommon "github.com/erigontech/erigon-lib/common" "github.com/erigontech/erigon-lib/common/datadir" + "github.com/erigontech/erigon-lib/common/fixedgas" "github.com/erigontech/erigon-lib/direct" "github.com/erigontech/erigon-lib/gointerfaces" proto_downloader "github.com/erigontech/erigon-lib/gointerfaces/downloader" @@ -310,8 +311,12 @@ func MockWithEverything(tb testing.TB, gspec *types.Genesis, key *ecdsa.PrivateK shanghaiTime := mock.ChainConfig.ShanghaiTime cancunTime := mock.ChainConfig.CancunTime pragueTime := mock.ChainConfig.PragueTime - maxBlobsPerBlock := mock.ChainConfig.GetMaxBlobsPerBlock() - mock.TxPool, err = txpool.New(newTxs, mock.DB, poolCfg, kvcache.NewDummy(), *chainID, shanghaiTime, nil /* agraBlock */, cancunTime, pragueTime, maxBlobsPerBlock, nil, logger) + maxBlobsPerBlock := mock.ChainConfig.GetMaxBlobsPerBlock(0) + maxBlobsPerBlockPrague := mock.ChainConfig.MaxBlobGasPerBlockPrague + if maxBlobsPerBlockPrague != nil { + *maxBlobsPerBlockPrague = *maxBlobsPerBlockPrague / fixedgas.BlobGasPerBlob + } + mock.TxPool, err = txpool.New(newTxs, mock.DB, poolCfg, kvcache.NewDummy(), *chainID, shanghaiTime, nil /* agraBlock */, cancunTime, pragueTime, maxBlobsPerBlock, maxBlobsPerBlockPrague, nil, logger) if err != nil { tb.Fatal(err) } diff --git a/turbo/stages/stageloop.go b/turbo/stages/stageloop.go index 7b0a49a2f5e..a42f30c7846 100644 --- a/turbo/stages/stageloop.go +++ b/turbo/stages/stageloop.go @@ -302,8 +302,13 @@ func (h *Hook) sendNotifications(notifications *shards.Notifications, tx kv.Tx, 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/turbo/transactions/call.go b/turbo/transactions/call.go index da29580bd09..34ff914f0fd 100644 --- a/turbo/transactions/call.go +++ b/turbo/transactions/call.go @@ -80,7 +80,7 @@ func DoCall( if err != nil { return nil, err } - blockCtx := NewEVMBlockContext(engine, header, blockNrOrHash.RequireCanonical, tx, headerReader) + blockCtx := NewEVMBlockContext(engine, header, blockNrOrHash.RequireCanonical, tx, headerReader, chainConfig) txCtx := core.NewEVMTxContext(msg) evm := vm.NewEVM(blockCtx, txCtx, state, chainConfig, vm.Config{NoBaseFee: true}) @@ -105,8 +105,8 @@ func DoCall( return result, nil } -func NewEVMBlockContext(engine consensus.EngineReader, header *types.Header, requireCanonical bool, tx kv.Tx, headerReader services.HeaderReader) evmtypes.BlockContext { - return core.NewEVMBlockContext(header, MakeHeaderGetter(requireCanonical, tx, headerReader), engine, nil /* author */) +func NewEVMBlockContext(engine consensus.EngineReader, header *types.Header, requireCanonical bool, tx kv.Tx, headerReader services.HeaderReader, config *chain.Config) evmtypes.BlockContext { + return core.NewEVMBlockContext(header, MakeHeaderGetter(requireCanonical, tx, headerReader), engine, nil /* author */, config) } func MakeHeaderGetter(requireCanonical bool, tx kv.Tx, headerReader services.HeaderReader) func(uint64) libcommon.Hash { @@ -212,7 +212,7 @@ func NewReusableCaller( return nil, err } - blockCtx := NewEVMBlockContext(engine, header, blockNrOrHash.RequireCanonical, tx, headerReader) + blockCtx := NewEVMBlockContext(engine, header, blockNrOrHash.RequireCanonical, tx, headerReader, chainConfig) txCtx := core.NewEVMTxContext(msg) evm := vm.NewEVM(blockCtx, txCtx, ibs, chainConfig, vm.Config{NoBaseFee: true}) diff --git a/turbo/transactions/tracing.go b/turbo/transactions/tracing.go index c09780d418d..c953ec11589 100644 --- a/turbo/transactions/tracing.go +++ b/turbo/transactions/tracing.go @@ -56,7 +56,7 @@ func ComputeTxEnv(ctx context.Context, engine consensus.EngineReader, block *typ } header := block.HeaderNoCopy() - blockContext := core.NewEVMBlockContext(header, core.GetHashFn(header, getHeader), engine, nil) + blockContext := core.NewEVMBlockContext(header, core.GetHashFn(header, getHeader), engine, nil, cfg) // Recompute transactions up to the target index. signer := types.MakeSigner(cfg, block.NumberU64(), block.Time())