From dcd05cd749f50bf983abe41d01c64ec103b8aafb Mon Sep 17 00:00:00 2001 From: lightclient Date: Fri, 13 Dec 2024 08:56:28 -0700 Subject: [PATCH 1/7] params: add blob schedule config --- params/config.go | 58 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/params/config.go b/params/config.go index 9b3b92484ab2..01fe8e201145 100644 --- a/params/config.go +++ b/params/config.go @@ -327,8 +327,9 @@ type ChainConfig struct { DepositContractAddress common.Address `json:"depositContractAddress,omitempty"` // Various consensus engines - Ethash *EthashConfig `json:"ethash,omitempty"` - Clique *CliqueConfig `json:"clique,omitempty"` + Ethash *EthashConfig `json:"ethash,omitempty"` + Clique *CliqueConfig `json:"clique,omitempty"` + BlobScheduleConfig *BlobScheduleConfig `json:"blobSchedule,omitempty"` } // EthashConfig is the consensus engine configs for proof-of-work based sealing. @@ -425,6 +426,59 @@ func (c *ChainConfig) Description() string { return banner } +// BlobConfig specifies the target and max blobs per block for the associated +// fork. +type BlobConfig struct { + Target uint64 `json:"target"` + Max uint64 `json:"max"` +} + +// BlobScheduleConfig determines target and max number of blobs allow per fork. +type BlobScheduleConfig struct { + Cancun *BlobConfig `json:"cancun,omitempty"` + Prague *BlobConfig `json:"prague,omitempty"` +} + +// LatestTargetBlobsPerBlock returns the target blobs per block associated with +// requested time. +func (c *ChainConfig) LatestTargetBlobsPerBlock(time uint64) uint64 { + if c.BlobScheduleConfig == nil { + panic("blob schedule not defined") + } + var ( + london = c.LondonBlock + s = c.BlobScheduleConfig + ) + switch { + case c.IsPrague(london, time) && s.Prague != nil: + return s.Prague.Target + case c.IsCancun(london, time) && s.Cancun != nil: + return s.Cancun.Target + default: + return 0 + } +} + +// LatestMaxBlobsPerBlock returns the max blobs per block associated with +// requested time. +func (c *ChainConfig) LatestMaxBlobsPerBlock(time uint64) uint64 { + if c.BlobScheduleConfig == nil { + panic("blob schedule not defined") + } + var ( + london = c.LondonBlock + s = c.BlobScheduleConfig + ) + switch { + case c.IsPrague(london, time) && s.Prague != nil: + return s.Prague.Max + case c.IsCancun(london, time) && s.Cancun != nil: + return s.Cancun.Max + default: + return 0 + } +} + // IsHomestead returns whether num is either equal to the homestead block or greater. func (c *ChainConfig) IsHomestead(num *big.Int) bool { return isBlockForked(c.HomesteadBlock, num) From 12933226c5f6068d109628f3cb31273ee5f63cac Mon Sep 17 00:00:00 2001 From: lightclient Date: Fri, 13 Dec 2024 10:41:46 -0700 Subject: [PATCH 2/7] all: hack config-based blob max and target into existing code --- consensus/beacon/consensus.go | 2 +- consensus/misc/eip4844/eip4844.go | 33 +++++++++++++++-------------- core/chain_makers.go | 10 +-------- core/state_processor_test.go | 7 +----- core/txpool/blobpool/blobpool.go | 4 ++-- core/txpool/blobpool/slotter.go | 2 +- core/txpool/validation.go | 6 +++--- eth/gasprice/feehistory.go | 5 ++--- internal/ethapi/simulate.go | 4 +--- internal/ethapi/transaction_args.go | 8 +++---- miner/worker.go | 11 ++++------ params/protocol_params.go | 3 --- 12 files changed, 37 insertions(+), 58 deletions(-) diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index cdacf354a5e6..5023e2fc5ccc 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -284,7 +284,7 @@ func (beacon *Beacon) verifyHeader(chain consensus.ChainHeaderReader, header, pa if header.ParentBeaconRoot == nil { return errors.New("header is missing beaconRoot") } - if err := eip4844.VerifyEIP4844Header(parent, header); err != nil { + if err := eip4844.VerifyEIP4844Header(chain.Config(), parent, header); err != nil { return err } } diff --git a/consensus/misc/eip4844/eip4844.go b/consensus/misc/eip4844/eip4844.go index 2dad9a0cd3de..3b59dfbea253 100644 --- a/consensus/misc/eip4844/eip4844.go +++ b/consensus/misc/eip4844/eip4844.go @@ -33,7 +33,7 @@ var ( // VerifyEIP4844Header verifies the presence of the excessBlobGas field and that // if the current block contains no transactions, the excessBlobGas is updated // accordingly. -func VerifyEIP4844Header(parent, header *types.Header) error { +func VerifyEIP4844Header(config *params.ChainConfig, parent, header *types.Header) error { // Verify the header is not malformed if header.ExcessBlobGas == nil { return errors.New("header is missing excessBlobGas") @@ -42,14 +42,26 @@ func VerifyEIP4844Header(parent, header *types.Header) error { return errors.New("header is missing blobGasUsed") } // Verify that the blob gas used remains within reasonable limits. - if *header.BlobGasUsed > params.MaxBlobGasPerBlock { - return fmt.Errorf("blob gas used %d exceeds maximum allowance %d", *header.BlobGasUsed, params.MaxBlobGasPerBlock) + if max := config.LatestMaxBlobsPerBlock(header.Time); *header.BlobGasUsed > max*params.BlobTxBlobGasPerBlob { + return fmt.Errorf("blob gas used %d exceeds maximum allowance %d", *header.BlobGasUsed, max) } if *header.BlobGasUsed%params.BlobTxBlobGasPerBlob != 0 { return fmt.Errorf("blob gas used %d not a multiple of blob gas per blob %d", header.BlobGasUsed, params.BlobTxBlobGasPerBlob) } // Verify the excessBlobGas is correct based on the parent header + expectedExcessBlobGas := CalcExcessBlobGas(config, parent) + if *header.ExcessBlobGas != expectedExcessBlobGas { + return fmt.Errorf("invalid excessBlobGas: have %d, want %d", + *header.ExcessBlobGas, expectedExcessBlobGas) + } + return nil +} + +// CalcExcessBlobGas calculates the excess blob gas after applying the set of +// blobs on top of the excess blob gas. +func CalcExcessBlobGas(config *params.ChainConfig, parent *types.Header) uint64 { var ( + target = config.LatestTargetBlobsPerBlock(parent.Time) * params.BlobTxBlobGasPerBlob parentExcessBlobGas uint64 parentBlobGasUsed uint64 ) @@ -57,22 +69,11 @@ func VerifyEIP4844Header(parent, header *types.Header) error { parentExcessBlobGas = *parent.ExcessBlobGas parentBlobGasUsed = *parent.BlobGasUsed } - expectedExcessBlobGas := CalcExcessBlobGas(parentExcessBlobGas, parentBlobGasUsed) - if *header.ExcessBlobGas != expectedExcessBlobGas { - return fmt.Errorf("invalid excessBlobGas: have %d, want %d, parent excessBlobGas %d, parent blobDataUsed %d", - *header.ExcessBlobGas, expectedExcessBlobGas, parentExcessBlobGas, parentBlobGasUsed) - } - return nil -} - -// CalcExcessBlobGas calculates the excess blob gas after applying the set of -// blobs on top of the excess blob gas. -func CalcExcessBlobGas(parentExcessBlobGas uint64, parentBlobGasUsed uint64) uint64 { excessBlobGas := parentExcessBlobGas + parentBlobGasUsed - if excessBlobGas < params.BlobTxTargetBlobGasPerBlock { + if excessBlobGas < target { return 0 } - return excessBlobGas - params.BlobTxTargetBlobGasPerBlock + return excessBlobGas - target } // CalcBlobFee calculates the blobfee from the header's excess blob gas field. diff --git a/core/chain_makers.go b/core/chain_makers.go index 26714845ebc8..c2840659df19 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -595,15 +595,7 @@ func (cm *chainMaker) makeHeader(parent *types.Block, state *state.StateDB, engi } } if cm.config.IsCancun(header.Number, header.Time) { - var ( - parentExcessBlobGas uint64 - parentBlobGasUsed uint64 - ) - if parent.ExcessBlobGas() != nil { - parentExcessBlobGas = *parent.ExcessBlobGas() - parentBlobGasUsed = *parent.BlobGasUsed() - } - excessBlobGas := eip4844.CalcExcessBlobGas(parentExcessBlobGas, parentBlobGasUsed) + excessBlobGas := eip4844.CalcExcessBlobGas(cm.config, parent.Header()) header.ExcessBlobGas = &excessBlobGas header.BlobGasUsed = new(uint64) header.ParentBeaconRoot = new(common.Hash) diff --git a/core/state_processor_test.go b/core/state_processor_test.go index 2f841eb64aed..b7c59b5124e7 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -425,12 +425,7 @@ func GenerateBadBlock(parent *types.Block, engine consensus.Engine, txs types.Tr } header.Root = common.BytesToHash(hasher.Sum(nil)) if config.IsCancun(header.Number, header.Time) { - var pExcess, pUsed = uint64(0), uint64(0) - if parent.ExcessBlobGas() != nil { - pExcess = *parent.ExcessBlobGas() - pUsed = *parent.BlobGasUsed() - } - excess := eip4844.CalcExcessBlobGas(pExcess, pUsed) + excess := eip4844.CalcExcessBlobGas(config, parent.Header()) used := uint64(nBlobs * params.BlobTxBlobGasPerBlob) header.ExcessBlobGas = &excess header.BlobGasUsed = &used diff --git a/core/txpool/blobpool/blobpool.go b/core/txpool/blobpool/blobpool.go index 02d339f99c2d..9a493a1ac998 100644 --- a/core/txpool/blobpool/blobpool.go +++ b/core/txpool/blobpool/blobpool.go @@ -54,7 +54,7 @@ const ( // maxBlobsPerTransaction is the maximum number of blobs a single transaction // is allowed to contain. Whilst the spec states it's unlimited, the block // data slots are protocol bound, which implicitly also limit this. - maxBlobsPerTransaction = params.MaxBlobGasPerBlock / params.BlobTxBlobGasPerBlob + // maxBlobsPerTransaction = params.MaxBlobGasPerBlock / params.BlobTxBlobGasPerBlob // txAvgSize is an approximate byte size of a transaction metadata to avoid // tiny overflows causing all txs to move a shelf higher, wasting disk space. @@ -1598,7 +1598,7 @@ func (p *BlobPool) updateStorageMetrics() { metrics.GetOrRegisterGauge(fmt.Sprintf(shelfSlotusedGaugeName, shelf.SlotSize/blobSize), nil).Update(int64(shelf.FilledSlots)) metrics.GetOrRegisterGauge(fmt.Sprintf(shelfSlotgapsGaugeName, shelf.SlotSize/blobSize), nil).Update(int64(shelf.GappedSlots)) - if shelf.SlotSize/blobSize > maxBlobsPerTransaction { + if uint64(shelf.SlotSize/blobSize) > p.chain.Config().LatestMaxBlobsPerBlock(p.head.Time)*params.BlobTxBlobGasPerBlob { oversizedDataused += slotDataused oversizedDatagaps += slotDatagaps oversizedSlotused += shelf.FilledSlots diff --git a/core/txpool/blobpool/slotter.go b/core/txpool/blobpool/slotter.go index 35349c3445cf..2478e6edd88b 100644 --- a/core/txpool/blobpool/slotter.go +++ b/core/txpool/blobpool/slotter.go @@ -31,7 +31,7 @@ func newSlotter() func() (uint32, bool) { return func() (size uint32, done bool) { slotsize += blobSize - finished := slotsize > maxBlobsPerTransaction*blobSize+txMaxSize + finished := slotsize > 9*blobSize+txMaxSize return slotsize, finished } diff --git a/core/txpool/validation.go b/core/txpool/validation.go index 412418dcc936..d2aa8dc9b725 100644 --- a/core/txpool/validation.go +++ b/core/txpool/validation.go @@ -134,9 +134,9 @@ func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types if len(hashes) == 0 { return errors.New("blobless blob transaction") } - if len(hashes) > params.MaxBlobGasPerBlock/params.BlobTxBlobGasPerBlob { - return fmt.Errorf("too many blobs in transaction: have %d, permitted %d", len(hashes), params.MaxBlobGasPerBlock/params.BlobTxBlobGasPerBlob) - } + // if len(hashes) > params.MaxBlobGasPerBlock/params.BlobTxBlobGasPerBlob { + // return fmt.Errorf("too many blobs in transaction: have %d, permitted %d", len(hashes), params.MaxBlobGasPerBlock/params.BlobTxBlobGasPerBlob) + // } // Ensure commitments, proofs and hashes are valid if err := validateBlobSidecar(hashes, sidecar); err != nil { return err diff --git a/eth/gasprice/feehistory.go b/eth/gasprice/feehistory.go index 1e625e21c029..af7f38abca36 100644 --- a/eth/gasprice/feehistory.go +++ b/eth/gasprice/feehistory.go @@ -31,7 +31,6 @@ import ( "github.com/ethereum/go-ethereum/consensus/misc/eip4844" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" ) @@ -98,7 +97,7 @@ 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 { bf.results.blobBaseFee = eip4844.CalcBlobFee(*excessBlobGas) - bf.results.nextBlobBaseFee = eip4844.CalcBlobFee(eip4844.CalcExcessBlobGas(*excessBlobGas, *bf.header.BlobGasUsed)) + bf.results.nextBlobBaseFee = eip4844.CalcBlobFee(eip4844.CalcExcessBlobGas(config, bf.header)) } else { bf.results.blobBaseFee = new(big.Int) bf.results.nextBlobBaseFee = new(big.Int) @@ -106,7 +105,7 @@ func (oracle *Oracle) processBlock(bf *blockFees, percentiles []float64) { // Compute gas used ratio for normal and blob gas. bf.results.gasUsedRatio = float64(bf.header.GasUsed) / float64(bf.header.GasLimit) if blobGasUsed := bf.header.BlobGasUsed; blobGasUsed != nil { - bf.results.blobGasUsedRatio = float64(*blobGasUsed) / params.MaxBlobGasPerBlock + bf.results.blobGasUsedRatio = float64(*blobGasUsed) / float64(config.LatestMaxBlobsPerBlock(bf.header.Time)) } if len(percentiles) == 0 { diff --git a/internal/ethapi/simulate.go b/internal/ethapi/simulate.go index 130eaa972458..a43bd5ca4375 100644 --- a/internal/ethapi/simulate.go +++ b/internal/ethapi/simulate.go @@ -159,9 +159,7 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header, if sim.chainConfig.IsCancun(header.Number, header.Time) { var excess uint64 if sim.chainConfig.IsCancun(parent.Number, parent.Time) { - excess = eip4844.CalcExcessBlobGas(*parent.ExcessBlobGas, *parent.BlobGasUsed) - } else { - excess = eip4844.CalcExcessBlobGas(0, 0) + excess = eip4844.CalcExcessBlobGas(sim.chainConfig, parent) } header.ExcessBlobGas = &excess } diff --git a/internal/ethapi/transaction_args.go b/internal/ethapi/transaction_args.go index a39a6666f497..a86e3d506415 100644 --- a/internal/ethapi/transaction_args.go +++ b/internal/ethapi/transaction_args.go @@ -32,14 +32,13 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto/kzg4844" "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" "github.com/holiman/uint256" ) -var ( - maxBlobsPerTransaction = params.MaxBlobGasPerBlock / params.BlobTxBlobGasPerBlob -) +// var ( +// maxBlobsPerTransaction = params.MaxBlobGasPerBlock / params.BlobTxBlobGasPerBlob +// ) // TransactionArgs represents the arguments to construct a new transaction // or a message call. @@ -125,6 +124,7 @@ func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend, skipGas if args.BlobHashes != nil && len(args.BlobHashes) == 0 { return errors.New(`need at least 1 blob for a blob transaction`) } + maxBlobsPerTransaction := int(b.ChainConfig().LatestMaxBlobsPerBlock(b.CurrentHeader().Time)) if args.BlobHashes != nil && len(args.BlobHashes) > maxBlobsPerTransaction { return fmt.Errorf(`too many blobs in transaction (have=%d, max=%d)`, len(args.BlobHashes), maxBlobsPerTransaction) } diff --git a/miner/worker.go b/miner/worker.go index b5aa08002591..e7c3e0f9e0b0 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -210,10 +210,7 @@ func (miner *Miner) prepareWork(genParams *generateParams, witness bool) (*envir if miner.chainConfig.IsCancun(header.Number, header.Time) { var excessBlobGas uint64 if miner.chainConfig.IsCancun(parent.Number, parent.Time) { - excessBlobGas = eip4844.CalcExcessBlobGas(*parent.ExcessBlobGas, *parent.BlobGasUsed) - } else { - // For the first post-fork block, both parent.data_gas_used and parent.excess_data_gas are evaluated as 0 - excessBlobGas = eip4844.CalcExcessBlobGas(0, 0) + excessBlobGas = eip4844.CalcExcessBlobGas(miner.chainConfig, parent) } header.BlobGasUsed = new(uint64) header.ExcessBlobGas = &excessBlobGas @@ -284,7 +281,7 @@ func (miner *Miner) commitBlobTransaction(env *environment, tx *types.Transactio // isn't really a better place right now. The blob gas limit is checked at block validation time // and not during execution. This means core.ApplyTransaction will not return an error if the // tx has too many blobs. So we have to explicitly check it here. - if (env.blobs+len(sc.Blobs))*params.BlobTxBlobGasPerBlob > params.MaxBlobGasPerBlock { + if (env.blobs+len(sc.Blobs))*params.BlobTxBlobGasPerBlob > int(miner.chainConfig.LatestMaxBlobsPerBlock(env.header.Time)*params.BlobTxBlobGasPerBlob) { return errors.New("max data blobs reached") } receipt, err := miner.applyTransaction(env, tx) @@ -333,7 +330,7 @@ func (miner *Miner) commitTransactions(env *environment, plainTxs, blobTxs *tran } // If we don't have enough blob space for any further blob transactions, // skip that list altogether - if !blobTxs.Empty() && env.blobs*params.BlobTxBlobGasPerBlob >= params.MaxBlobGasPerBlock { + if !blobTxs.Empty() && env.blobs*params.BlobTxBlobGasPerBlob >= int(miner.chainConfig.LatestMaxBlobsPerBlock(env.header.Time)*params.BlobTxBlobGasPerBlob) { log.Trace("Not enough blob space for further blob transactions") blobTxs.Clear() // Fall though to pick up any plain txs @@ -367,7 +364,7 @@ func (miner *Miner) commitTransactions(env *environment, plainTxs, blobTxs *tran txs.Pop() continue } - if left := uint64(params.MaxBlobGasPerBlock - env.blobs*params.BlobTxBlobGasPerBlob); left < ltx.BlobGas { + if left := uint64(int(miner.chainConfig.LatestMaxBlobsPerBlock(env.header.Time)*params.BlobTxBlobGasPerBlob) - env.blobs*params.BlobTxBlobGasPerBlob); left < ltx.BlobGas { log.Trace("Not enough blob gas left for transaction", "hash", ltx.Hash, "left", left, "needed", ltx.BlobGas) txs.Pop() continue diff --git a/params/protocol_params.go b/params/protocol_params.go index b46e8d66b255..5180f9c565bd 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -173,9 +173,6 @@ const ( BlobTxBlobGaspriceUpdateFraction = 3338477 // Controls the maximum rate of change for blob gas price BlobTxPointEvaluationPrecompileGas = 50000 // Gas price for the point evaluation precompile. - BlobTxTargetBlobGasPerBlock = 3 * BlobTxBlobGasPerBlob // Target consumable blob gas for data blobs per block (for 1559-like pricing) - MaxBlobGasPerBlock = 6 * BlobTxBlobGasPerBlob // Maximum consumable blob gas for data blobs per block - HistoryServeWindow = 8192 // Number of blocks to serve historical block hashes for, EIP-2935. ) From b43e9060188727d251d14eac4a622354c254af53 Mon Sep 17 00:00:00 2001 From: lightclient Date: Wed, 8 Jan 2025 18:31:53 -0700 Subject: [PATCH 3/7] all: add blob schedule where relevant --- .../internal/ethtest/testdata/genesis.json | 10 ++- cmd/evm/internal/t8ntool/execution.go | 11 +++- consensus/misc/eip4844/eip4844.go | 4 +- consensus/misc/eip4844/eip4844_test.go | 30 ++++++--- core/chain_makers_test.go | 6 +- core/state_processor_test.go | 20 +----- core/txpool/blobpool/blobpool.go | 19 +++--- core/txpool/blobpool/blobpool_test.go | 12 ++-- core/txpool/blobpool/limbo.go | 4 +- core/txpool/blobpool/slotter.go | 4 +- core/txpool/blobpool/slotter_test.go | 2 +- eth/catalyst/api_test.go | 3 + eth/fetcher/tx_fetcher_test.go | 6 +- eth/gasprice/feehistory.go | 2 +- eth/gasprice/gasprice_test.go | 6 ++ eth/tracers/internal/tracetest/supply_test.go | 1 + .../testdata/call_tracer/blob_tx.json | 8 ++- .../testdata/prestate_tracer/blob_tx.json | 12 +++- .../testdata/prestate_tracer/setcode_tx.json | 12 +++- eth/tracers/internal/tracetest/util.go | 2 +- ethclient/ethclient_test.go | 10 +-- internal/ethapi/transaction_args.go | 2 +- miner/worker.go | 18 ++++-- params/config.go | 64 +++++++++++++++++-- tests/init.go | 32 ++++++++++ tests/state_test_util.go | 2 +- 26 files changed, 218 insertions(+), 84 deletions(-) diff --git a/cmd/devp2p/internal/ethtest/testdata/genesis.json b/cmd/devp2p/internal/ethtest/testdata/genesis.json index 4cfebdcac10d..25f8769618c7 100644 --- a/cmd/devp2p/internal/ethtest/testdata/genesis.json +++ b/cmd/devp2p/internal/ethtest/testdata/genesis.json @@ -18,7 +18,13 @@ "shanghaiTime": 780, "cancunTime": 840, "terminalTotalDifficulty": 9454784, - "ethash": {} + "ethash": {}, + "blobSchedule": { + "cancun": { + "target": 3, + "max": 6 + } + } }, "nonce": "0x0", "timestamp": "0x0", @@ -108,4 +114,4 @@ "baseFeePerGas": null, "excessBlobGas": null, "blobGasUsed": null -} \ No newline at end of file +} diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index aef497885ed9..d53ebf40e07b 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -190,7 +190,14 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, parentExcessBlobGas := pre.Env.ParentExcessBlobGas parentBlobGasUsed := pre.Env.ParentBlobGasUsed if parentExcessBlobGas != nil && parentBlobGasUsed != nil { - excessBlobGas = eip4844.CalcExcessBlobGas(*parentExcessBlobGas, *parentBlobGasUsed) + parent := &types.Header{ + ParentHash: common.Hash{}, + Number: new(big.Int).SetUint64(pre.Env.Number - 1), + Time: pre.Env.ParentTimestamp, + ExcessBlobGas: pre.Env.ParentExcessBlobGas, + BlobGasUsed: pre.Env.ParentBlobGasUsed, + } + excessBlobGas = eip4844.CalcExcessBlobGas(chainConfig, parent) vmContext.BlobBaseFee = eip4844.CalcBlobFee(excessBlobGas) } } @@ -234,7 +241,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, txBlobGas := uint64(0) if tx.Type() == types.BlobTxType { txBlobGas = uint64(params.BlobTxBlobGasPerBlob * len(tx.BlobHashes())) - if used, max := blobGasUsed+txBlobGas, uint64(params.MaxBlobGasPerBlock); used > max { + if used, max := blobGasUsed+txBlobGas, chainConfig.MaxBlobsPerBlock(pre.Env.Number)*params.BlobTxBlobGasPerBlob; used > max { err := fmt.Errorf("blob gas (%d) would exceed maximum allowance %d", used, max) log.Warn("rejected tx", "index", i, "err", err) rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()}) diff --git a/consensus/misc/eip4844/eip4844.go b/consensus/misc/eip4844/eip4844.go index 3b59dfbea253..7d3006fa3bbf 100644 --- a/consensus/misc/eip4844/eip4844.go +++ b/consensus/misc/eip4844/eip4844.go @@ -42,7 +42,7 @@ func VerifyEIP4844Header(config *params.ChainConfig, parent, header *types.Heade return errors.New("header is missing blobGasUsed") } // Verify that the blob gas used remains within reasonable limits. - if max := config.LatestMaxBlobsPerBlock(header.Time); *header.BlobGasUsed > max*params.BlobTxBlobGasPerBlob { + if max := config.MaxBlobsPerBlock(header.Time) * params.BlobTxBlobGasPerBlob; *header.BlobGasUsed > max { return fmt.Errorf("blob gas used %d exceeds maximum allowance %d", *header.BlobGasUsed, max) } if *header.BlobGasUsed%params.BlobTxBlobGasPerBlob != 0 { @@ -61,7 +61,7 @@ func VerifyEIP4844Header(config *params.ChainConfig, parent, header *types.Heade // blobs on top of the excess blob gas. func CalcExcessBlobGas(config *params.ChainConfig, parent *types.Header) uint64 { var ( - target = config.LatestTargetBlobsPerBlock(parent.Time) * params.BlobTxBlobGasPerBlob + target = config.TargetBlobsPerBlock(parent.Time) * params.BlobTxBlobGasPerBlob parentExcessBlobGas uint64 parentBlobGasUsed uint64 ) diff --git a/consensus/misc/eip4844/eip4844_test.go b/consensus/misc/eip4844/eip4844_test.go index ec417380fcb0..20a4b4507877 100644 --- a/consensus/misc/eip4844/eip4844_test.go +++ b/consensus/misc/eip4844/eip4844_test.go @@ -21,10 +21,16 @@ import ( "math/big" "testing" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" ) func TestCalcExcessBlobGas(t *testing.T) { + var ( + config = params.MainnetChainConfig + targetBlobs = config.TargetBlobsPerBlock(*config.CancunTime) + targetBlobGas = targetBlobs * params.BlobTxBlobGasPerBlob + ) var tests = []struct { excess uint64 blobs uint64 @@ -34,23 +40,29 @@ func TestCalcExcessBlobGas(t *testing.T) { // slots are below - or equal - to the target. {0, 0, 0}, {0, 1, 0}, - {0, params.BlobTxTargetBlobGasPerBlock / params.BlobTxBlobGasPerBlob, 0}, + {0, targetBlobs, 0}, // If the target blob gas is exceeded, the excessBlobGas should increase // by however much it was overshot - {0, (params.BlobTxTargetBlobGasPerBlock / params.BlobTxBlobGasPerBlob) + 1, params.BlobTxBlobGasPerBlob}, - {1, (params.BlobTxTargetBlobGasPerBlock / params.BlobTxBlobGasPerBlob) + 1, params.BlobTxBlobGasPerBlob + 1}, - {1, (params.BlobTxTargetBlobGasPerBlock / params.BlobTxBlobGasPerBlob) + 2, 2*params.BlobTxBlobGasPerBlob + 1}, + {0, targetBlobs + 1, params.BlobTxBlobGasPerBlob}, + {1, targetBlobs + 1, params.BlobTxBlobGasPerBlob + 1}, + {1, targetBlobs + 2, 2*params.BlobTxBlobGasPerBlob + 1}, // The excess blob gas should decrease by however much the target was // under-shot, capped at zero. - {params.BlobTxTargetBlobGasPerBlock, params.BlobTxTargetBlobGasPerBlock / params.BlobTxBlobGasPerBlob, params.BlobTxTargetBlobGasPerBlock}, - {params.BlobTxTargetBlobGasPerBlock, (params.BlobTxTargetBlobGasPerBlock / params.BlobTxBlobGasPerBlob) - 1, params.BlobTxTargetBlobGasPerBlock - params.BlobTxBlobGasPerBlob}, - {params.BlobTxTargetBlobGasPerBlock, (params.BlobTxTargetBlobGasPerBlock / params.BlobTxBlobGasPerBlob) - 2, params.BlobTxTargetBlobGasPerBlock - (2 * params.BlobTxBlobGasPerBlob)}, - {params.BlobTxBlobGasPerBlob - 1, (params.BlobTxTargetBlobGasPerBlock / params.BlobTxBlobGasPerBlob) - 1, 0}, + {targetBlobGas, targetBlobs, targetBlobGas}, + {targetBlobGas, targetBlobs - 1, targetBlobGas - params.BlobTxBlobGasPerBlob}, + {targetBlobGas, targetBlobs - 2, targetBlobGas - (2 * params.BlobTxBlobGasPerBlob)}, + {params.BlobTxBlobGasPerBlob - 1, targetBlobs - 1, 0}, } for i, tt := range tests { - result := CalcExcessBlobGas(tt.excess, tt.blobs*params.BlobTxBlobGasPerBlob) + blobGasUsed := tt.blobs * params.BlobTxBlobGasPerBlob + parent := &types.Header{ + Time: *config.CancunTime, + ExcessBlobGas: &tt.excess, + BlobGasUsed: &blobGasUsed, + } + result := CalcExcessBlobGas(config, parent) if result != tt.want { t.Errorf("test %d: excess blob gas mismatch: have %v, want %v", i, result, tt.want) } diff --git a/core/chain_makers_test.go b/core/chain_makers_test.go index f72e6285dfa3..b3b1ffde4a31 100644 --- a/core/chain_makers_test.go +++ b/core/chain_makers_test.go @@ -42,7 +42,7 @@ func TestGeneratePOSChain(t *testing.T) { aa = common.Address{0xaa} bb = common.Address{0xbb} funds = big.NewInt(0).Mul(big.NewInt(1337), big.NewInt(params.Ether)) - config = *params.AllEthashProtocolChanges + config = *params.MergedTestChainConfig gspec = &Genesis{ Config: &config, Alloc: types.GenesisAlloc{ @@ -57,10 +57,6 @@ func TestGeneratePOSChain(t *testing.T) { db = rawdb.NewMemoryDatabase() ) - config.TerminalTotalDifficulty = common.Big0 - config.ShanghaiTime = u64(0) - config.CancunTime = u64(0) - // init 0xaa with some storage elements storage := make(map[common.Hash]common.Hash) storage[common.Hash{0x00}] = common.Hash{0x00} diff --git a/core/state_processor_test.go b/core/state_processor_test.go index b7c59b5124e7..b17c0ad2b2e8 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -46,25 +46,7 @@ func u64(val uint64) *uint64 { return &val } // contain invalid transactions func TestStateProcessorErrors(t *testing.T) { var ( - config = ¶ms.ChainConfig{ - ChainID: big.NewInt(1), - HomesteadBlock: big.NewInt(0), - EIP150Block: big.NewInt(0), - EIP155Block: big.NewInt(0), - EIP158Block: big.NewInt(0), - ByzantiumBlock: big.NewInt(0), - ConstantinopleBlock: big.NewInt(0), - PetersburgBlock: big.NewInt(0), - IstanbulBlock: big.NewInt(0), - MuirGlacierBlock: big.NewInt(0), - BerlinBlock: big.NewInt(0), - LondonBlock: big.NewInt(0), - Ethash: new(params.EthashConfig), - TerminalTotalDifficulty: big.NewInt(0), - ShanghaiTime: new(uint64), - CancunTime: new(uint64), - PragueTime: new(uint64), - } + config = params.MergedTestChainConfig signer = types.LatestSigner(config) key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") key2, _ = crypto.HexToECDSA("0202020202020202020202020202020202020202020202020202002020202020") diff --git a/core/txpool/blobpool/blobpool.go b/core/txpool/blobpool/blobpool.go index 9a493a1ac998..fae00978e792 100644 --- a/core/txpool/blobpool/blobpool.go +++ b/core/txpool/blobpool/blobpool.go @@ -51,11 +51,6 @@ const ( // transaction. There can be multiple of these embedded into a single tx. blobSize = params.BlobTxFieldElementsPerBlob * params.BlobTxBytesPerFieldElement - // maxBlobsPerTransaction is the maximum number of blobs a single transaction - // is allowed to contain. Whilst the spec states it's unlimited, the block - // data slots are protocol bound, which implicitly also limit this. - // maxBlobsPerTransaction = params.MaxBlobGasPerBlock / params.BlobTxBlobGasPerBlob - // txAvgSize is an approximate byte size of a transaction metadata to avoid // tiny overflows causing all txs to move a shelf higher, wasting disk space. txAvgSize = 4 * 1024 @@ -223,6 +218,11 @@ func newBlobTxMeta(id uint64, size uint32, tx *types.Transaction) *blobTxMeta { // very relaxed ones can be included even if the fees go up, when the closer // ones could already be invalid. // +// - Because the maximum number of blobs allowed in a block can change per +// fork, the pool is designed to handle the maximum number of blobs allowed +// in the chain's latest defined fork -- even if it isn't active. This +// avoids needing to upgrade the database around the fork boundary. +// // When the pool eventually reaches saturation, some old transactions - that may // never execute - will need to be evicted in favor of newer ones. The eviction // strategy is quite complex: @@ -387,7 +387,8 @@ func (p *BlobPool) Init(gasTip uint64, head *types.Header, reserve txpool.Addres fails = append(fails, id) } } - store, err := billy.Open(billy.Options{Path: queuedir, Repair: true}, newSlotter(), index) + slotter := newSlotter(p.chain.Config().LatestMaxBlobsPerBlock()) + store, err := billy.Open(billy.Options{Path: queuedir, Repair: true}, slotter, index) if err != nil { return err } @@ -420,7 +421,7 @@ func (p *BlobPool) Init(gasTip uint64, head *types.Header, reserve txpool.Addres // Pool initialized, attach the blob limbo to it to track blobs included // recently but not yet finalized - p.limbo, err = newLimbo(limbodir) + p.limbo, err = newLimbo(limbodir, p.chain.Config().LatestMaxBlobsPerBlock()) if err != nil { p.Close() return err @@ -1598,7 +1599,7 @@ func (p *BlobPool) updateStorageMetrics() { metrics.GetOrRegisterGauge(fmt.Sprintf(shelfSlotusedGaugeName, shelf.SlotSize/blobSize), nil).Update(int64(shelf.FilledSlots)) metrics.GetOrRegisterGauge(fmt.Sprintf(shelfSlotgapsGaugeName, shelf.SlotSize/blobSize), nil).Update(int64(shelf.GappedSlots)) - if uint64(shelf.SlotSize/blobSize) > p.chain.Config().LatestMaxBlobsPerBlock(p.head.Time)*params.BlobTxBlobGasPerBlob { + if shelf.SlotSize/blobSize > uint32(p.chain.Config().LatestMaxBlobsPerBlock()*params.BlobTxBlobGasPerBlob) { oversizedDataused += slotDataused oversizedDatagaps += slotDatagaps oversizedSlotused += shelf.FilledSlots @@ -1751,7 +1752,7 @@ func (p *BlobPool) Clear() { // The transaction addition may attempt to reserve the sender addr which // can't happen until Clear releases the reservation lock. Clear cannot // acquire the subpool lock until the transaction addition is completed. - for acct, _ := range p.index { + for acct := range p.index { p.reserve(acct, false) } p.lookup = newLookup() diff --git a/core/txpool/blobpool/blobpool_test.go b/core/txpool/blobpool/blobpool_test.go index e4441bec5dad..d982a96ac298 100644 --- a/core/txpool/blobpool/blobpool_test.go +++ b/core/txpool/blobpool/blobpool_test.go @@ -51,6 +51,8 @@ var ( testBlobVHashes [][32]byte ) +const testMaxBlobsPerBlock = 6 + func init() { for i := 0; i < 10; i++ { testBlob := &kzg4844.Blob{byte(i)} @@ -415,7 +417,7 @@ func TestOpenDrops(t *testing.T) { defer os.RemoveAll(storage) os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700) - store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(), nil) + store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(testMaxBlobsPerBlock), nil) // Insert a malformed transaction to verify that decoding errors (or format // changes) are handled gracefully (case 1) @@ -738,7 +740,7 @@ func TestOpenIndex(t *testing.T) { defer os.RemoveAll(storage) os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700) - store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(), nil) + store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(testMaxBlobsPerBlock), nil) // Insert a sequence of transactions with varying price points to check that // the cumulative minimum will be maintained. @@ -827,7 +829,7 @@ func TestOpenHeap(t *testing.T) { defer os.RemoveAll(storage) os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700) - store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(), nil) + store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(testMaxBlobsPerBlock), nil) // Insert a few transactions from a few accounts. To remove randomness from // the heap initialization, use a deterministic account/tx/priority ordering. @@ -914,7 +916,7 @@ func TestOpenCap(t *testing.T) { defer os.RemoveAll(storage) os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700) - store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(), nil) + store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(testMaxBlobsPerBlock), nil) // Insert a few transactions from a few accounts var ( @@ -1369,7 +1371,7 @@ func TestAdd(t *testing.T) { defer os.RemoveAll(storage) // late defer, still ok os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700) - store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(), nil) + store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(testMaxBlobsPerBlock), nil) // Insert the seed transactions for the pool startup var ( diff --git a/core/txpool/blobpool/limbo.go b/core/txpool/blobpool/limbo.go index 32381a393613..f2af1fca1af9 100644 --- a/core/txpool/blobpool/limbo.go +++ b/core/txpool/blobpool/limbo.go @@ -48,7 +48,7 @@ type limbo struct { } // newLimbo opens and indexes a set of limboed blob transactions. -func newLimbo(datadir string) (*limbo, error) { +func newLimbo(datadir string, maxBlobsPerTransaction uint64) (*limbo, error) { l := &limbo{ index: make(map[common.Hash]uint64), groups: make(map[uint64]map[uint64]common.Hash), @@ -60,7 +60,7 @@ func newLimbo(datadir string) (*limbo, error) { fails = append(fails, id) } } - store, err := billy.Open(billy.Options{Path: datadir, Repair: true}, newSlotter(), index) + store, err := billy.Open(billy.Options{Path: datadir, Repair: true}, newSlotter(maxBlobsPerTransaction), index) if err != nil { return nil, err } diff --git a/core/txpool/blobpool/slotter.go b/core/txpool/blobpool/slotter.go index 2478e6edd88b..cc8aa387c708 100644 --- a/core/txpool/blobpool/slotter.go +++ b/core/txpool/blobpool/slotter.go @@ -25,13 +25,13 @@ package blobpool // The slotter also creates a shelf for 0-blob transactions. Whilst those are not // allowed in the current protocol, having an empty shelf is not a relevant use // of resources, but it makes stress testing with junk transactions simpler. -func newSlotter() func() (uint32, bool) { +func newSlotter(maxBlobsPerTransaction uint64) func() (uint32, bool) { slotsize := uint32(txAvgSize) slotsize -= uint32(blobSize) // underflows, it's ok, will overflow back in the first return return func() (size uint32, done bool) { slotsize += blobSize - finished := slotsize > 9*blobSize+txMaxSize + finished := slotsize > uint32(maxBlobsPerTransaction)*blobSize+txMaxSize return slotsize, finished } diff --git a/core/txpool/blobpool/slotter_test.go b/core/txpool/blobpool/slotter_test.go index a7b43b4d2224..8d46f47d2ca6 100644 --- a/core/txpool/blobpool/slotter_test.go +++ b/core/txpool/blobpool/slotter_test.go @@ -21,7 +21,7 @@ import "testing" // Tests that the slotter creates the expected database shelves. func TestNewSlotter(t *testing.T) { // Generate the database shelve sizes - slotter := newSlotter() + slotter := newSlotter(6) var shelves []uint32 for { diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index e0a155f12b8d..89c5d0edfeb7 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -1310,6 +1310,7 @@ func setupBodies(t *testing.T) (*node.Node, *eth.Ethereum, []*types.Block) { genesis.Config.ShanghaiTime = &time genesis.Config.CancunTime = &time genesis.Config.PragueTime = &time + genesis.Config.BlobScheduleConfig = params.DefaultBlobSchedule n, ethservice := startEthService(t, genesis, blocks) @@ -1626,6 +1627,7 @@ func TestParentBeaconBlockRoot(t *testing.T) { time := blocks[len(blocks)-1].Time() + 5 genesis.Config.ShanghaiTime = &time genesis.Config.CancunTime = &time + genesis.Config.BlobScheduleConfig = params.DefaultBlobSchedule n, ethservice := startEthService(t, genesis, blocks) defer n.Close() @@ -1708,6 +1710,7 @@ func TestWitnessCreationAndConsumption(t *testing.T) { timestamp := blocks[len(blocks)-2].Time() + 5 genesis.Config.ShanghaiTime = ×tamp genesis.Config.CancunTime = ×tamp + genesis.Config.BlobScheduleConfig = params.DefaultBlobSchedule n, ethservice := startEthService(t, genesis, blocks[:9]) defer n.Close() diff --git a/eth/fetcher/tx_fetcher_test.go b/eth/fetcher/tx_fetcher_test.go index f80b1d6096d3..52b35910862d 100644 --- a/eth/fetcher/tx_fetcher_test.go +++ b/eth/fetcher/tx_fetcher_test.go @@ -1108,7 +1108,7 @@ func TestTransactionFetcherBandwidthLimiting(t *testing.T) { doTxNotify{peer: "C", hashes: []common.Hash{{0x07}, {0x08}}, types: []byte{types.BlobTxType, types.BlobTxType}, - sizes: []uint32{params.MaxBlobGasPerBlock, params.MaxBlobGasPerBlock}, + sizes: []uint32{params.BlobTxBlobGasPerBlob * 10, params.BlobTxBlobGasPerBlob * 10}, }, doWait{time: txArriveTimeout, step: true}, isWaiting(nil), @@ -1125,8 +1125,8 @@ func TestTransactionFetcherBandwidthLimiting(t *testing.T) { {common.Hash{0x06}, types.LegacyTxType, maxTxRetrievalSize}, }, "C": { - {common.Hash{0x07}, types.BlobTxType, params.MaxBlobGasPerBlock}, - {common.Hash{0x08}, types.BlobTxType, params.MaxBlobGasPerBlock}, + {common.Hash{0x07}, types.BlobTxType, params.BlobTxBlobGasPerBlob * 10}, + {common.Hash{0x08}, types.BlobTxType, params.BlobTxBlobGasPerBlob * 10}, }, }, fetching: map[string][]common.Hash{ diff --git a/eth/gasprice/feehistory.go b/eth/gasprice/feehistory.go index af7f38abca36..b2be7e201cb6 100644 --- a/eth/gasprice/feehistory.go +++ b/eth/gasprice/feehistory.go @@ -105,7 +105,7 @@ func (oracle *Oracle) processBlock(bf *blockFees, percentiles []float64) { // Compute gas used ratio for normal and blob gas. bf.results.gasUsedRatio = float64(bf.header.GasUsed) / float64(bf.header.GasLimit) if blobGasUsed := bf.header.BlobGasUsed; blobGasUsed != nil { - bf.results.blobGasUsedRatio = float64(*blobGasUsed) / float64(config.LatestMaxBlobsPerBlock(bf.header.Time)) + bf.results.blobGasUsedRatio = float64(*blobGasUsed) / float64(config.MaxBlobsPerBlock(bf.header.Time)) } if len(percentiles) == 0 { diff --git a/eth/gasprice/gasprice_test.go b/eth/gasprice/gasprice_test.go index fdba2e584b42..f002a826256f 100644 --- a/eth/gasprice/gasprice_test.go +++ b/eth/gasprice/gasprice_test.go @@ -155,6 +155,12 @@ func newTestBackend(t *testing.T, londonBlock *big.Int, cancunBlock *big.Int, pe ts := gspec.Timestamp + cancunBlock.Uint64()*10 // fixed 10 sec block time in blockgen config.ShanghaiTime = &ts config.CancunTime = &ts + config.BlobScheduleConfig = ¶ms.BlobScheduleConfig{ + Cancun: ¶ms.BlobConfig{ + Target: 3, + Max: 6, + }, + } signer = types.LatestSigner(gspec.Config) } diff --git a/eth/tracers/internal/tracetest/supply_test.go b/eth/tracers/internal/tracetest/supply_test.go index 6f06b7c0d5be..6cd1dc857d84 100644 --- a/eth/tracers/internal/tracetest/supply_test.go +++ b/eth/tracers/internal/tracetest/supply_test.go @@ -360,6 +360,7 @@ func TestSupplySelfdestruct(t *testing.T) { cancunTime := uint64(0) gspec.Config.ShanghaiTime = &cancunTime gspec.Config.CancunTime = &cancunTime + gspec.Config.BlobScheduleConfig = params.DefaultBlobSchedule postCancunOutput, postCancunChain, err := testSupplyTracer(t, gspec, testBlockGenerationFunc) if err != nil { diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/blob_tx.json b/eth/tracers/internal/tracetest/testdata/call_tracer/blob_tx.json index 05da3b42e194..d1e1cd33fcc2 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/blob_tx.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/blob_tx.json @@ -41,7 +41,13 @@ "grayGlacierBlock": 0, "shanghaiTime": 0, "cancunTime": 0, - "terminalTotalDifficulty": 0 + "terminalTotalDifficulty": 0, + "blobSchedule": { + "cancun": { + "target": 3, + "max": 6 + } + } } }, "context": { diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer/blob_tx.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer/blob_tx.json index f8adbabf6377..06b1004f41f6 100644 --- a/eth/tracers/internal/tracetest/testdata/prestate_tracer/blob_tx.json +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer/blob_tx.json @@ -41,7 +41,13 @@ "grayGlacierBlock": 0, "shanghaiTime": 0, "cancunTime": 0, - "terminalTotalDifficulty": 0 + "terminalTotalDifficulty": 0, + "blobSchedule": { + "cancun": { + "target": 3, + "max": 6 + } + } } }, "context": { @@ -54,7 +60,9 @@ }, "input": "0x03f8b1820539806485174876e800825208940c2c51a0990aee1d73c1228de1586883415575088080c083020000f842a00100c9fbdf97f747e85847b4f3fff408f89c26842f77c882858bf2c89923849aa00138e3896f3c27f2389147507f8bcec52028b0efca6ee842ed83c9158873943880a0dbac3f97a532c9b00e6239b29036245a5bfbb96940b9d848634661abee98b945a03eec8525f261c2e79798f7b45a5d6ccaefa24576d53ba5023e919b86841c0675", "result": { - "0x0000000000000000000000000000000000000000": { "balance": "0x272e0528" }, + "0x0000000000000000000000000000000000000000": { + "balance": "0x272e0528" + }, "0x0c2c51a0990aee1d73c1228de158688341557508": { "balance": "0xde0b6b3a7640000" } diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer/setcode_tx.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer/setcode_tx.json index b7d5ee1c54b9..af683a252390 100644 --- a/eth/tracers/internal/tracetest/testdata/prestate_tracer/setcode_tx.json +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer/setcode_tx.json @@ -53,7 +53,17 @@ "shanghaiTime": 0, "cancunTime": 0, "pragueTime": 0, - "terminalTotalDifficulty": 0 + "terminalTotalDifficulty": 0, + "blobSchedule": { + "cancun": { + "target": 3, + "max": 6 + }, + "prauge": { + "target": 3, + "max": 6 + } + } } }, "context": { diff --git a/eth/tracers/internal/tracetest/util.go b/eth/tracers/internal/tracetest/util.go index abc2699498d4..e938c0a9d281 100644 --- a/eth/tracers/internal/tracetest/util.go +++ b/eth/tracers/internal/tracetest/util.go @@ -53,7 +53,7 @@ func (c *callContext) toBlockContext(genesis *core.Genesis) vm.BlockContext { } if genesis.ExcessBlobGas != nil && genesis.BlobGasUsed != nil { - excessBlobGas := eip4844.CalcExcessBlobGas(*genesis.ExcessBlobGas, *genesis.BlobGasUsed) + excessBlobGas := eip4844.CalcExcessBlobGas(genesis.Config, genesis.ToBlock().Header()) context.BlobBaseFee = eip4844.CalcBlobFee(excessBlobGas) } return context diff --git a/ethclient/ethclient_test.go b/ethclient/ethclient_test.go index 4ad8a552d268..360e0e9e0ab9 100644 --- a/ethclient/ethclient_test.go +++ b/ethclient/ethclient_test.go @@ -29,7 +29,7 @@ import ( "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/consensus/ethash" + "github.com/ethereum/go-ethereum/consensus/beacon" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" @@ -65,7 +65,7 @@ var ( ) var genesis = &core.Genesis{ - Config: params.AllEthashProtocolChanges, + Config: params.AllDevChainProtocolChanges, Alloc: types.GenesisAlloc{ testAddr: {Balance: testBalance}, revertContractAddr: {Code: revertCode}, @@ -136,7 +136,7 @@ func generateTestChain() []*types.Block { g.AddTx(testTx2) } } - _, blocks, _ := core.GenerateChainWithGenesis(genesis, ethash.NewFaker(), 2, generate) + _, blocks, _ := core.GenerateChainWithGenesis(genesis, beacon.NewFaker(), 2, generate) return append([]*types.Block{genesis.ToBlock()}, blocks...) } @@ -223,7 +223,7 @@ func testHeader(t *testing.T, chain []*types.Block, client *rpc.Client) { if got != nil && got.Number != nil && got.Number.Sign() == 0 { got.Number = big.NewInt(0) // hack to make DeepEqual work } - if !reflect.DeepEqual(got, tt.want) { + if got.Hash() != tt.want.Hash() { t.Fatalf("HeaderByNumber(%v) got = %v, want %v", tt.block, got, tt.want) } }) @@ -314,7 +314,7 @@ func testChainID(t *testing.T, client *rpc.Client) { if err != nil { t.Fatalf("unexpected error: %v", err) } - if id == nil || id.Cmp(params.AllEthashProtocolChanges.ChainID) != 0 { + if id == nil || id.Cmp(params.AllDevChainProtocolChanges.ChainID) != 0 { t.Fatalf("ChainID returned wrong number: %+v", id) } } diff --git a/internal/ethapi/transaction_args.go b/internal/ethapi/transaction_args.go index a86e3d506415..53233576c009 100644 --- a/internal/ethapi/transaction_args.go +++ b/internal/ethapi/transaction_args.go @@ -124,7 +124,7 @@ func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend, skipGas if args.BlobHashes != nil && len(args.BlobHashes) == 0 { return errors.New(`need at least 1 blob for a blob transaction`) } - maxBlobsPerTransaction := int(b.ChainConfig().LatestMaxBlobsPerBlock(b.CurrentHeader().Time)) + maxBlobsPerTransaction := int(b.ChainConfig().MaxBlobsPerBlock(b.CurrentHeader().Time)) if args.BlobHashes != nil && len(args.BlobHashes) > maxBlobsPerTransaction { return fmt.Errorf(`too many blobs in transaction (have=%d, max=%d)`, len(args.BlobHashes), maxBlobsPerTransaction) } diff --git a/miner/worker.go b/miner/worker.go index e7c3e0f9e0b0..ffdcd7dede46 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -281,7 +281,7 @@ func (miner *Miner) commitBlobTransaction(env *environment, tx *types.Transactio // isn't really a better place right now. The blob gas limit is checked at block validation time // and not during execution. This means core.ApplyTransaction will not return an error if the // tx has too many blobs. So we have to explicitly check it here. - if (env.blobs+len(sc.Blobs))*params.BlobTxBlobGasPerBlob > int(miner.chainConfig.LatestMaxBlobsPerBlock(env.header.Time)*params.BlobTxBlobGasPerBlob) { + if (env.blobs+len(sc.Blobs))*params.BlobTxBlobGasPerBlob > int(miner.chainConfig.MaxBlobsPerBlock(env.header.Time)*params.BlobTxBlobGasPerBlob) { return errors.New("max data blobs reached") } receipt, err := miner.applyTransaction(env, tx) @@ -330,7 +330,7 @@ func (miner *Miner) commitTransactions(env *environment, plainTxs, blobTxs *tran } // If we don't have enough blob space for any further blob transactions, // skip that list altogether - if !blobTxs.Empty() && env.blobs*params.BlobTxBlobGasPerBlob >= int(miner.chainConfig.LatestMaxBlobsPerBlock(env.header.Time)*params.BlobTxBlobGasPerBlob) { + if !blobTxs.Empty() && env.blobs*params.BlobTxBlobGasPerBlob >= int(miner.chainConfig.MaxBlobsPerBlock(env.header.Time)*params.BlobTxBlobGasPerBlob) { log.Trace("Not enough blob space for further blob transactions") blobTxs.Clear() // Fall though to pick up any plain txs @@ -364,10 +364,16 @@ func (miner *Miner) commitTransactions(env *environment, plainTxs, blobTxs *tran txs.Pop() continue } - if left := uint64(int(miner.chainConfig.LatestMaxBlobsPerBlock(env.header.Time)*params.BlobTxBlobGasPerBlob) - env.blobs*params.BlobTxBlobGasPerBlob); left < ltx.BlobGas { - log.Trace("Not enough blob gas left for transaction", "hash", ltx.Hash, "left", left, "needed", ltx.BlobGas) - txs.Pop() - continue + + // Most of the blob gas logic works regardless if the chain supports blobs + // or not, however the max check panics when called on a chain without a + // defined schedule, so we need to verify it's safe to call. + if miner.chainConfig.IsCancun(env.header.Number, env.header.Time) { + if left := uint64(int(miner.chainConfig.MaxBlobsPerBlock(env.header.Time)*params.BlobTxBlobGasPerBlob) - env.blobs*params.BlobTxBlobGasPerBlob); left < ltx.BlobGas { + log.Trace("Not enough blob gas left for transaction", "hash", ltx.Hash, "left", left, "needed", ltx.BlobGas) + txs.Pop() + continue + } } // Transaction seems to fit, pull it up from the pool tx := ltx.Resolve() diff --git a/params/config.go b/params/config.go index 01fe8e201145..aee706764ba9 100644 --- a/params/config.go +++ b/params/config.go @@ -60,6 +60,12 @@ var ( CancunTime: newUint64(1710338135), DepositContractAddress: common.HexToAddress("0x00000000219ab540356cbb839cbe05303d7705fa"), Ethash: new(EthashConfig), + BlobScheduleConfig: &BlobScheduleConfig{ + Cancun: &BlobConfig{ + Target: 3, + Max: 6, + }, + }, } // HoleskyChainConfig contains the chain parameters to run a node on the Holesky test network. HoleskyChainConfig = &ChainConfig{ @@ -157,6 +163,16 @@ var ( CancunTime: newUint64(0), TerminalTotalDifficulty: big.NewInt(0), PragueTime: newUint64(0), + BlobScheduleConfig: &BlobScheduleConfig{ + Cancun: &BlobConfig{ + Target: 3, + Max: 6, + }, + Prague: &BlobConfig{ + Target: 6, + Max: 9, + }, + }, } // AllCliqueProtocolChanges contains every protocol change (EIPs) introduced @@ -244,6 +260,16 @@ var ( TerminalTotalDifficulty: big.NewInt(0), Ethash: new(EthashConfig), Clique: nil, + BlobScheduleConfig: &BlobScheduleConfig{ + Cancun: &BlobConfig{ + Target: 3, + Max: 6, + }, + Prague: &BlobConfig{ + Target: 6, + Max: 9, + }, + }, } // NonActivatedConfig defines the chain configuration without activating @@ -277,6 +303,19 @@ var ( TestRules = TestChainConfig.Rules(new(big.Int), false, 0) ) +var ( + DefaultBlobSchedule = &BlobScheduleConfig{ + Cancun: &BlobConfig{ + Target: 3, + Max: 6, + }, + Prague: &BlobConfig{ + Target: 6, + Max: 9, + }, + } +) + // NetworkNames are user friendly names to use in the chain spec banner. var NetworkNames = map[string]string{ MainnetChainConfig.ChainID.String(): "mainnet", @@ -439,9 +478,9 @@ type BlobScheduleConfig struct { Prague *BlobConfig `json:"prague,omitempty"` } -// LatestTargetBlobsPerBlock returns the target blobs per block associated with +// TargetBlobsPerBlock returns the target blobs per block associated with // requested time. -func (c *ChainConfig) LatestTargetBlobsPerBlock(time uint64) uint64 { +func (c *ChainConfig) TargetBlobsPerBlock(time uint64) uint64 { if c.BlobScheduleConfig == nil { panic("blob schedule not defined") } @@ -459,9 +498,9 @@ func (c *ChainConfig) LatestTargetBlobsPerBlock(time uint64) uint64 { } } -// LatestMaxBlobsPerBlock returns the max blobs per block associated with +// MaxBlobsPerBlock returns the max blobs per block associated with // requested time. -func (c *ChainConfig) LatestMaxBlobsPerBlock(time uint64) uint64 { +func (c *ChainConfig) MaxBlobsPerBlock(time uint64) uint64 { if c.BlobScheduleConfig == nil { panic("blob schedule not defined") } @@ -479,6 +518,23 @@ func (c *ChainConfig) LatestMaxBlobsPerBlock(time uint64) uint64 { } } +// LatestMaxBlobsPerBlock returns the latest max blobs per block defined by the +// configuration, regardless of the currently active fork. +func (c *ChainConfig) LatestMaxBlobsPerBlock() uint64 { + s := c.BlobScheduleConfig + if s == nil { + return 0 + } + switch { + case s.Prague != nil: + return s.Prague.Max + case s.Cancun != nil: + return s.Cancun.Max + default: + panic("blob schedule empty") + } +} + // IsHomestead returns whether num is either equal to the homestead block or greater. func (c *ChainConfig) IsHomestead(num *big.Int) bool { return isBlockForked(c.HomesteadBlock, num) diff --git a/tests/init.go b/tests/init.go index 4bb83f9300bc..04422ea0d3d6 100644 --- a/tests/init.go +++ b/tests/init.go @@ -334,6 +334,12 @@ var Forks = map[string]*params.ChainConfig{ TerminalTotalDifficulty: big.NewInt(0), ShanghaiTime: u64(0), CancunTime: u64(0), + BlobScheduleConfig: ¶ms.BlobScheduleConfig{ + Cancun: ¶ms.BlobConfig{ + Target: 3, + Max: 6, + }, + }, }, "ShanghaiToCancunAtTime15k": { ChainID: big.NewInt(1), @@ -353,6 +359,12 @@ var Forks = map[string]*params.ChainConfig{ TerminalTotalDifficulty: big.NewInt(0), ShanghaiTime: u64(0), CancunTime: u64(15_000), + BlobScheduleConfig: ¶ms.BlobScheduleConfig{ + Cancun: ¶ms.BlobConfig{ + Target: 3, + Max: 6, + }, + }, }, "Prague": { ChainID: big.NewInt(1), @@ -374,6 +386,16 @@ var Forks = map[string]*params.ChainConfig{ CancunTime: u64(0), PragueTime: u64(0), DepositContractAddress: params.MainnetChainConfig.DepositContractAddress, + BlobScheduleConfig: ¶ms.BlobScheduleConfig{ + Cancun: ¶ms.BlobConfig{ + Target: 3, + Max: 6, + }, + Prague: ¶ms.BlobConfig{ + Target: 6, + Max: 9, + }, + }, }, "CancunToPragueAtTime15k": { ChainID: big.NewInt(1), @@ -395,6 +417,16 @@ var Forks = map[string]*params.ChainConfig{ CancunTime: u64(0), PragueTime: u64(15_000), DepositContractAddress: params.MainnetChainConfig.DepositContractAddress, + BlobScheduleConfig: ¶ms.BlobScheduleConfig{ + Cancun: ¶ms.BlobConfig{ + Target: 3, + Max: 6, + }, + Prague: ¶ms.BlobConfig{ + Target: 6, + Max: 9, + }, + }, }, } diff --git a/tests/state_test_util.go b/tests/state_test_util.go index 6e66bbaa7218..7232857fa226 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -281,7 +281,7 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh // - the block body is verified against the header in block_validator.go:ValidateBody // Here, we just do this shortcut smaller fix, since state tests do not // utilize those codepaths - if len(msg.BlobHashes)*params.BlobTxBlobGasPerBlob > params.MaxBlobGasPerBlock { + if config.IsCancun(new(big.Int), block.Time()) && uint64(len(msg.BlobHashes)) > config.MaxBlobsPerBlock(block.Time()) { return st, common.Hash{}, 0, errors.New("blob gas exceeds maximum") } } From d7183b5d8266bb6b21bbfe6965dff3eabd5e8696 Mon Sep 17 00:00:00 2001 From: lightclient Date: Thu, 9 Jan 2025 06:41:59 -0700 Subject: [PATCH 4/7] all: some more cleanup --- cmd/evm/internal/t8ntool/execution.go | 5 +---- consensus/misc/eip4844/eip4844.go | 3 +-- core/txpool/blobpool/blobpool.go | 2 +- core/txpool/validation.go | 6 +++--- internal/ethapi/transaction_args.go | 8 ++------ miner/worker.go | 24 +++++++++++++----------- 6 files changed, 21 insertions(+), 27 deletions(-) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index d53ebf40e07b..bddccc0a8ef6 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -191,8 +191,6 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, parentBlobGasUsed := pre.Env.ParentBlobGasUsed if parentExcessBlobGas != nil && parentBlobGasUsed != nil { parent := &types.Header{ - ParentHash: common.Hash{}, - Number: new(big.Int).SetUint64(pre.Env.Number - 1), Time: pre.Env.ParentTimestamp, ExcessBlobGas: pre.Env.ParentExcessBlobGas, BlobGasUsed: pre.Env.ParentBlobGasUsed, @@ -240,8 +238,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, } txBlobGas := uint64(0) if tx.Type() == types.BlobTxType { - txBlobGas = uint64(params.BlobTxBlobGasPerBlob * len(tx.BlobHashes())) - if used, max := blobGasUsed+txBlobGas, chainConfig.MaxBlobsPerBlock(pre.Env.Number)*params.BlobTxBlobGasPerBlob; used > max { + if used, max := uint64(len(tx.BlobHashes())+1), chainConfig.MaxBlobsPerBlock(pre.Env.Number); used > max { err := fmt.Errorf("blob gas (%d) would exceed maximum allowance %d", used, max) log.Warn("rejected tx", "index", i, "err", err) rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()}) diff --git a/consensus/misc/eip4844/eip4844.go b/consensus/misc/eip4844/eip4844.go index 7d3006fa3bbf..3e1fb4d7656c 100644 --- a/consensus/misc/eip4844/eip4844.go +++ b/consensus/misc/eip4844/eip4844.go @@ -51,8 +51,7 @@ func VerifyEIP4844Header(config *params.ChainConfig, parent, header *types.Heade // Verify the excessBlobGas is correct based on the parent header expectedExcessBlobGas := CalcExcessBlobGas(config, parent) if *header.ExcessBlobGas != expectedExcessBlobGas { - return fmt.Errorf("invalid excessBlobGas: have %d, want %d", - *header.ExcessBlobGas, expectedExcessBlobGas) + return fmt.Errorf("invalid excessBlobGas: have %d, want %d", *header.ExcessBlobGas, expectedExcessBlobGas) } return nil } diff --git a/core/txpool/blobpool/blobpool.go b/core/txpool/blobpool/blobpool.go index fae00978e792..db0f7ba4cfae 100644 --- a/core/txpool/blobpool/blobpool.go +++ b/core/txpool/blobpool/blobpool.go @@ -1599,7 +1599,7 @@ func (p *BlobPool) updateStorageMetrics() { metrics.GetOrRegisterGauge(fmt.Sprintf(shelfSlotusedGaugeName, shelf.SlotSize/blobSize), nil).Update(int64(shelf.FilledSlots)) metrics.GetOrRegisterGauge(fmt.Sprintf(shelfSlotgapsGaugeName, shelf.SlotSize/blobSize), nil).Update(int64(shelf.GappedSlots)) - if shelf.SlotSize/blobSize > uint32(p.chain.Config().LatestMaxBlobsPerBlock()*params.BlobTxBlobGasPerBlob) { + if shelf.SlotSize/blobSize > uint32(p.chain.Config().LatestMaxBlobsPerBlock()) { oversizedDataused += slotDataused oversizedDatagaps += slotDatagaps oversizedSlotused += shelf.FilledSlots diff --git a/core/txpool/validation.go b/core/txpool/validation.go index d2aa8dc9b725..f450689d0751 100644 --- a/core/txpool/validation.go +++ b/core/txpool/validation.go @@ -134,9 +134,9 @@ func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types if len(hashes) == 0 { return errors.New("blobless blob transaction") } - // if len(hashes) > params.MaxBlobGasPerBlock/params.BlobTxBlobGasPerBlob { - // return fmt.Errorf("too many blobs in transaction: have %d, permitted %d", len(hashes), params.MaxBlobGasPerBlock/params.BlobTxBlobGasPerBlob) - // } + if max := opts.Config.MaxBlobsPerBlock(head.Time); uint64(len(hashes)) > max { + return fmt.Errorf("too many blobs in transaction: have %d, permitted %d", len(hashes), max) + } // Ensure commitments, proofs and hashes are valid if err := validateBlobSidecar(hashes, sidecar); err != nil { return err diff --git a/internal/ethapi/transaction_args.go b/internal/ethapi/transaction_args.go index 53233576c009..964f1252576d 100644 --- a/internal/ethapi/transaction_args.go +++ b/internal/ethapi/transaction_args.go @@ -36,10 +36,6 @@ import ( "github.com/holiman/uint256" ) -// var ( -// maxBlobsPerTransaction = params.MaxBlobGasPerBlock / params.BlobTxBlobGasPerBlob -// ) - // TransactionArgs represents the arguments to construct a new transaction // or a message call. type TransactionArgs struct { @@ -124,8 +120,8 @@ func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend, skipGas if args.BlobHashes != nil && len(args.BlobHashes) == 0 { return errors.New(`need at least 1 blob for a blob transaction`) } - maxBlobsPerTransaction := int(b.ChainConfig().MaxBlobsPerBlock(b.CurrentHeader().Time)) - if args.BlobHashes != nil && len(args.BlobHashes) > maxBlobsPerTransaction { + maxBlobsPerTransaction := b.ChainConfig().LatestMaxBlobsPerBlock() + if args.BlobHashes != nil && uint64(len(args.BlobHashes)) > maxBlobsPerTransaction { return fmt.Errorf(`too many blobs in transaction (have=%d, max=%d)`, len(args.BlobHashes), maxBlobsPerTransaction) } diff --git a/miner/worker.go b/miner/worker.go index ffdcd7dede46..1bdb86c55f3c 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -281,7 +281,7 @@ func (miner *Miner) commitBlobTransaction(env *environment, tx *types.Transactio // isn't really a better place right now. The blob gas limit is checked at block validation time // and not during execution. This means core.ApplyTransaction will not return an error if the // tx has too many blobs. So we have to explicitly check it here. - if (env.blobs+len(sc.Blobs))*params.BlobTxBlobGasPerBlob > int(miner.chainConfig.MaxBlobsPerBlock(env.header.Time)*params.BlobTxBlobGasPerBlob) { + if env.blobs+len(sc.Blobs) > int(miner.chainConfig.MaxBlobsPerBlock(env.header.Time)) { return errors.New("max data blobs reached") } receipt, err := miner.applyTransaction(env, tx) @@ -330,7 +330,7 @@ func (miner *Miner) commitTransactions(env *environment, plainTxs, blobTxs *tran } // If we don't have enough blob space for any further blob transactions, // skip that list altogether - if !blobTxs.Empty() && env.blobs*params.BlobTxBlobGasPerBlob >= int(miner.chainConfig.MaxBlobsPerBlock(env.header.Time)*params.BlobTxBlobGasPerBlob) { + if !blobTxs.Empty() && env.blobs >= int(miner.chainConfig.MaxBlobsPerBlock(env.header.Time)) { log.Trace("Not enough blob space for further blob transactions") blobTxs.Clear() // Fall though to pick up any plain txs @@ -365,15 +365,17 @@ func (miner *Miner) commitTransactions(env *environment, plainTxs, blobTxs *tran continue } - // Most of the blob gas logic works regardless if the chain supports blobs - // or not, however the max check panics when called on a chain without a - // defined schedule, so we need to verify it's safe to call. - if miner.chainConfig.IsCancun(env.header.Number, env.header.Time) { - if left := uint64(int(miner.chainConfig.MaxBlobsPerBlock(env.header.Time)*params.BlobTxBlobGasPerBlob) - env.blobs*params.BlobTxBlobGasPerBlob); left < ltx.BlobGas { - log.Trace("Not enough blob gas left for transaction", "hash", ltx.Hash, "left", left, "needed", ltx.BlobGas) - txs.Pop() - continue - } + // Most of the blob gas logic here is agnostic as to if the chain supports + // blobs or not, however the max check panics when called on a chain without + // a defined schedule, so we need to verify it's safe to call. + if !miner.chainConfig.IsCancun(env.header.Number, env.header.Time) && ltx.Tx.Type() == types.BlobTxType { + log.Trace("Ignoring blob transaction before Cancun", "hash", ltx.Hash) + } + // Now it's safe to check if the transaction fits within the blob gas limit. + if left := miner.chainConfig.MaxBlobsPerBlock(env.header.Time) - uint64(env.blobs); left < ltx.BlobGas { + log.Trace("Not enough blob space left for transaction", "hash", ltx.Hash, "left", left, "needed", ltx.BlobGas) + txs.Pop() + continue } // Transaction seems to fit, pull it up from the pool tx := ltx.Resolve() From 4f2a76764069c1843e2e09129a37fe010dc45709 Mon Sep 17 00:00:00 2001 From: lightclient Date: Thu, 9 Jan 2025 06:55:21 -0700 Subject: [PATCH 5/7] all: simplify predefinied blob configurations --- eth/gasprice/gasprice_test.go | 7 +---- params/config.go | 52 ++++++++++++++++------------------- tests/init.go | 30 ++++---------------- 3 files changed, 31 insertions(+), 58 deletions(-) diff --git a/eth/gasprice/gasprice_test.go b/eth/gasprice/gasprice_test.go index f002a826256f..1ce3493194ef 100644 --- a/eth/gasprice/gasprice_test.go +++ b/eth/gasprice/gasprice_test.go @@ -155,12 +155,7 @@ func newTestBackend(t *testing.T, londonBlock *big.Int, cancunBlock *big.Int, pe ts := gspec.Timestamp + cancunBlock.Uint64()*10 // fixed 10 sec block time in blockgen config.ShanghaiTime = &ts config.CancunTime = &ts - config.BlobScheduleConfig = ¶ms.BlobScheduleConfig{ - Cancun: ¶ms.BlobConfig{ - Target: 3, - Max: 6, - }, - } + config.BlobScheduleConfig = params.DefaultBlobSchedule signer = types.LatestSigner(gspec.Config) } diff --git a/params/config.go b/params/config.go index aee706764ba9..3d951adafff4 100644 --- a/params/config.go +++ b/params/config.go @@ -61,10 +61,7 @@ var ( DepositContractAddress: common.HexToAddress("0x00000000219ab540356cbb839cbe05303d7705fa"), Ethash: new(EthashConfig), BlobScheduleConfig: &BlobScheduleConfig{ - Cancun: &BlobConfig{ - Target: 3, - Max: 6, - }, + Cancun: DefaultCancunBlobConfig, }, } // HoleskyChainConfig contains the chain parameters to run a node on the Holesky test network. @@ -90,6 +87,9 @@ var ( ShanghaiTime: newUint64(1696000704), CancunTime: newUint64(1707305664), Ethash: new(EthashConfig), + BlobScheduleConfig: &BlobScheduleConfig{ + Cancun: DefaultCancunBlobConfig, + }, } // SepoliaChainConfig contains the chain parameters to run a node on the Sepolia test network. SepoliaChainConfig = &ChainConfig{ @@ -114,6 +114,9 @@ var ( ShanghaiTime: newUint64(1677557088), CancunTime: newUint64(1706655072), Ethash: new(EthashConfig), + BlobScheduleConfig: &BlobScheduleConfig{ + Cancun: DefaultCancunBlobConfig, + }, } // AllEthashProtocolChanges contains every protocol change (EIPs) introduced // and accepted by the Ethereum core developers into the Ethash consensus. @@ -164,14 +167,8 @@ var ( TerminalTotalDifficulty: big.NewInt(0), PragueTime: newUint64(0), BlobScheduleConfig: &BlobScheduleConfig{ - Cancun: &BlobConfig{ - Target: 3, - Max: 6, - }, - Prague: &BlobConfig{ - Target: 6, - Max: 9, - }, + Cancun: DefaultCancunBlobConfig, + Prague: DefaultPragueBlobConfig, }, } @@ -261,14 +258,8 @@ var ( Ethash: new(EthashConfig), Clique: nil, BlobScheduleConfig: &BlobScheduleConfig{ - Cancun: &BlobConfig{ - Target: 3, - Max: 6, - }, - Prague: &BlobConfig{ - Target: 6, - Max: 9, - }, + Cancun: DefaultCancunBlobConfig, + Prague: DefaultPragueBlobConfig, }, } @@ -304,15 +295,20 @@ var ( ) var ( + // DefaultCancunBlobConfig is the default blob configuration for the Cancun fork. + DefaultCancunBlobConfig = &BlobConfig{ + Target: 3, + Max: 6, + } + // DefaultPragueBlobConfig is the default blob configuration for the Cancun fork. + DefaultPragueBlobConfig = &BlobConfig{ + Target: 6, + Max: 9, + } + // DefaultBlobSchedule is the latest configured blob schedule for test chains. DefaultBlobSchedule = &BlobScheduleConfig{ - Cancun: &BlobConfig{ - Target: 3, - Max: 6, - }, - Prague: &BlobConfig{ - Target: 6, - Max: 9, - }, + Cancun: DefaultCancunBlobConfig, + Prague: DefaultPragueBlobConfig, } ) diff --git a/tests/init.go b/tests/init.go index 04422ea0d3d6..4f4fcb48f357 100644 --- a/tests/init.go +++ b/tests/init.go @@ -335,10 +335,7 @@ var Forks = map[string]*params.ChainConfig{ ShanghaiTime: u64(0), CancunTime: u64(0), BlobScheduleConfig: ¶ms.BlobScheduleConfig{ - Cancun: ¶ms.BlobConfig{ - Target: 3, - Max: 6, - }, + Cancun: params.DefaultCancunBlobConfig, }, }, "ShanghaiToCancunAtTime15k": { @@ -360,10 +357,7 @@ var Forks = map[string]*params.ChainConfig{ ShanghaiTime: u64(0), CancunTime: u64(15_000), BlobScheduleConfig: ¶ms.BlobScheduleConfig{ - Cancun: ¶ms.BlobConfig{ - Target: 3, - Max: 6, - }, + Cancun: params.DefaultCancunBlobConfig, }, }, "Prague": { @@ -387,14 +381,8 @@ var Forks = map[string]*params.ChainConfig{ PragueTime: u64(0), DepositContractAddress: params.MainnetChainConfig.DepositContractAddress, BlobScheduleConfig: ¶ms.BlobScheduleConfig{ - Cancun: ¶ms.BlobConfig{ - Target: 3, - Max: 6, - }, - Prague: ¶ms.BlobConfig{ - Target: 6, - Max: 9, - }, + Cancun: params.DefaultCancunBlobConfig, + Prague: params.DefaultPragueBlobConfig, }, }, "CancunToPragueAtTime15k": { @@ -418,14 +406,8 @@ var Forks = map[string]*params.ChainConfig{ PragueTime: u64(15_000), DepositContractAddress: params.MainnetChainConfig.DepositContractAddress, BlobScheduleConfig: ¶ms.BlobScheduleConfig{ - Cancun: ¶ms.BlobConfig{ - Target: 3, - Max: 6, - }, - Prague: ¶ms.BlobConfig{ - Target: 6, - Max: 9, - }, + Cancun: params.DefaultCancunBlobConfig, + Prague: params.DefaultPragueBlobConfig, }, }, } From 780bb6a7a0605320db08037fa3d9e0f9dc7ebb9b Mon Sep 17 00:00:00 2001 From: lightclient Date: Thu, 9 Jan 2025 06:56:37 -0700 Subject: [PATCH 6/7] miner: add missing continue --- miner/worker.go | 1 + 1 file changed, 1 insertion(+) diff --git a/miner/worker.go b/miner/worker.go index 1bdb86c55f3c..4313507e7013 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -370,6 +370,7 @@ func (miner *Miner) commitTransactions(env *environment, plainTxs, blobTxs *tran // a defined schedule, so we need to verify it's safe to call. if !miner.chainConfig.IsCancun(env.header.Number, env.header.Time) && ltx.Tx.Type() == types.BlobTxType { log.Trace("Ignoring blob transaction before Cancun", "hash", ltx.Hash) + continue } // Now it's safe to check if the transaction fits within the blob gas limit. if left := miner.chainConfig.MaxBlobsPerBlock(env.header.Time) - uint64(env.blobs); left < ltx.BlobGas { From aee56ab54b0c5bee6c7c0a1af50c93574ede9747 Mon Sep 17 00:00:00 2001 From: lightclient Date: Thu, 9 Jan 2025 07:46:53 -0700 Subject: [PATCH 7/7] miner,t8n: fix a couple small bugs --- cmd/evm/internal/t8ntool/execution.go | 1 + miner/worker.go | 16 +++++++--------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index bddccc0a8ef6..c798e34abb57 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -238,6 +238,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, } txBlobGas := uint64(0) if tx.Type() == types.BlobTxType { + txBlobGas = uint64(params.BlobTxBlobGasPerBlob * len(tx.BlobHashes())) if used, max := uint64(len(tx.BlobHashes())+1), chainConfig.MaxBlobsPerBlock(pre.Env.Number); used > max { err := fmt.Errorf("blob gas (%d) would exceed maximum allowance %d", used, max) log.Warn("rejected tx", "index", i, "err", err) diff --git a/miner/worker.go b/miner/worker.go index 4313507e7013..811876b45bfb 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -368,16 +368,14 @@ func (miner *Miner) commitTransactions(env *environment, plainTxs, blobTxs *tran // Most of the blob gas logic here is agnostic as to if the chain supports // blobs or not, however the max check panics when called on a chain without // a defined schedule, so we need to verify it's safe to call. - if !miner.chainConfig.IsCancun(env.header.Number, env.header.Time) && ltx.Tx.Type() == types.BlobTxType { - log.Trace("Ignoring blob transaction before Cancun", "hash", ltx.Hash) - continue - } - // Now it's safe to check if the transaction fits within the blob gas limit. - if left := miner.chainConfig.MaxBlobsPerBlock(env.header.Time) - uint64(env.blobs); left < ltx.BlobGas { - log.Trace("Not enough blob space left for transaction", "hash", ltx.Hash, "left", left, "needed", ltx.BlobGas) - txs.Pop() - continue + if miner.chainConfig.IsCancun(env.header.Number, env.header.Time) { + if left := miner.chainConfig.MaxBlobsPerBlock(env.header.Time) - uint64(env.blobs); left < ltx.BlobGas { + log.Trace("Not enough blob space left for transaction", "hash", ltx.Hash, "left", left, "needed", ltx.BlobGas) + txs.Pop() + continue + } } + // Transaction seems to fit, pull it up from the pool tx := ltx.Resolve() if tx == nil {