sync l1datafee change for curie (#888)

* update rollup/rcfg/config.go

* update consensus/misc/curie.go

* update rollup/fees/rollup_fee_test.go

* update rollup/fees/rollup_fee.go

* update rollup/tracing/tracing.go

* update tests/state_test_util.go

* update light/txpool.go

* fix some

* update eth/tracers/internal/tracetest/prestate_test.go

* update eth/tracers/api.go

* update core/chain_makers.go

* update core/state_processor.go

* update cmd/evm/internal/t8ntool/execution.go

* update txpool

* update ethclient/ethclient_test.go

* update ethclient/gethclient/gethclient_test.go

* update core/blockchain_test.go

* update miner/worker.go

* update txpool 2
This commit is contained in:
HAOYUatHZ 2024-07-09 20:45:54 +08:00 committed by GitHub
parent 5e255cf5b1
commit f777318776
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
31 changed files with 367 additions and 103 deletions

View file

@ -715,7 +715,7 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM
vmEnv := vm.NewEVM(evmContext, txContext, stateDB, b.config, vm.Config{NoBaseFee: true}) vmEnv := vm.NewEVM(evmContext, txContext, stateDB, b.config, vm.Config{NoBaseFee: true})
gasPool := new(core.GasPool).AddGas(math.MaxUint64) gasPool := new(core.GasPool).AddGas(math.MaxUint64)
signer := types.MakeSigner(b.blockchain.Config(), header.Number, header.Time) signer := types.MakeSigner(b.blockchain.Config(), header.Number, header.Time)
l1DataFee, err := fees.EstimateL1DataFeeForMessage(msg, header.BaseFee, b.blockchain.Config().ChainID, signer, stateDB) l1DataFee, err := fees.EstimateL1DataFeeForMessage(msg, header.BaseFee, b.blockchain.Config(), signer, stateDB, header.Number)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -186,6 +186,10 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
chainConfig.DAOForkBlock.Cmp(new(big.Int).SetUint64(pre.Env.Number)) == 0 { chainConfig.DAOForkBlock.Cmp(new(big.Int).SetUint64(pre.Env.Number)) == 0 {
misc.ApplyDAOHardFork(statedb) misc.ApplyDAOHardFork(statedb)
} }
// Apply Curie hard fork
if chainConfig.CurieBlock != nil && chainConfig.CurieBlock.Cmp(new(big.Int).SetUint64(pre.Env.Number)) == 0 {
misc.ApplyCurieHardFork(statedb)
}
if beaconRoot := pre.Env.ParentBeaconBlockRoot; beaconRoot != nil { if beaconRoot := pre.Env.ParentBeaconBlockRoot; beaconRoot != nil {
evm := vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vmConfig) evm := vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vmConfig)
core.ProcessBeaconBlockRoot(*beaconRoot, evm, statedb) core.ProcessBeaconBlockRoot(*beaconRoot, evm, statedb)
@ -221,7 +225,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
) )
evm := vm.NewEVM(vmContext, txContext, statedb, chainConfig, vmConfig) evm := vm.NewEVM(vmContext, txContext, statedb, chainConfig, vmConfig)
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb) l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, chainConfig, new(big.Int).SetUint64(pre.Env.Number))
if err != nil { if err != nil {
log.Info("rejected tx due to fees.CalculateL1DataFee", "index", i, "hash", tx.Hash(), "from", msg.From, "error", err) log.Info("rejected tx due to fees.CalculateL1DataFee", "index", i, "hash", tx.Hash(), "from", msg.From, "error", err)
rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()}) rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()})

23
consensus/misc/curie.go Normal file
View file

@ -0,0 +1,23 @@
package misc
import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rollup/rcfg"
)
// ApplyCurieHardFork modifies the state database according to the Curie hard-fork rules,
// updating the bytecode and storage of the L1GasPriceOracle contract.
func ApplyCurieHardFork(statedb *state.StateDB) {
log.Info("Applying Curie hard fork")
// update contract byte code
statedb.SetCode(rcfg.L1GasPriceOracleAddress, rcfg.CurieL1GasPriceOracleBytecode)
// initialize new storage slots
statedb.SetState(rcfg.L1GasPriceOracleAddress, rcfg.IsCurieSlot, common.BytesToHash([]byte{1}))
statedb.SetState(rcfg.L1GasPriceOracleAddress, rcfg.L1BlobBaseFeeSlot, common.BytesToHash([]byte{1}))
statedb.SetState(rcfg.L1GasPriceOracleAddress, rcfg.CommitScalarSlot, common.BigToHash(rcfg.InitialCommitScalar))
statedb.SetState(rcfg.L1GasPriceOracleAddress, rcfg.BlobScalarSlot, common.BigToHash(rcfg.InitialBlobScalar))
}

View file

@ -17,6 +17,7 @@
package core package core
import ( import (
"encoding/json"
"errors" "errors"
"fmt" "fmt"
"math/big" "math/big"
@ -39,7 +40,9 @@ import (
"github.com/ethereum/go-ethereum/eth/tracers/logger" "github.com/ethereum/go-ethereum/eth/tracers/logger"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rollup/rcfg"
"github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie"
"github.com/stretchr/testify/assert"
) )
// So we can deterministically seed different blockchains // So we can deterministically seed different blockchains
@ -4716,3 +4719,78 @@ func TestEIP3651(t *testing.T) {
t.Fatalf("sender balance incorrect: expected %d, got %d", expected, actual) t.Fatalf("sender balance incorrect: expected %d, got %d", expected, actual)
} }
} }
func TestCurieTransition(t *testing.T) {
// Set fork blocks in config
// (we make a deep copy to avoid interference with other tests)
var config *params.ChainConfig
b, _ := json.Marshal(params.AllEthashProtocolChanges)
json.Unmarshal(b, &config)
config.CurieBlock = big.NewInt(2)
config.DescartesBlock = nil
var (
db = rawdb.NewMemoryDatabase()
gspec = &Genesis{Config: config}
genesis = gspec.MustCommit(db, trie.NewDatabase(db, trie.HashDefaults))
)
blockchain, _ := NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
defer blockchain.Stop()
blocks, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 4, nil)
if _, err := blockchain.InsertChain(blocks); err != nil {
t.Fatal(err)
}
latestBlock := uint64(4)
assert.Equal(t, latestBlock, blockchain.CurrentHeader().Number.Uint64())
for ii := uint64(0); ii <= latestBlock; ii++ {
block := blockchain.GetBlockByNumber(ii)
number := block.Number().Uint64()
baseFee := block.BaseFee()
statedb, _ := state.New(block.Root(), state.NewDatabase(db), nil)
code := statedb.GetCode(rcfg.L1GasPriceOracleAddress)
codeSize := statedb.GetCodeSize(rcfg.L1GasPriceOracleAddress)
keccakCodeHash := statedb.GetKeccakCodeHash(rcfg.L1GasPriceOracleAddress)
poseidonCodeHash := statedb.GetPoseidonCodeHash(rcfg.L1GasPriceOracleAddress)
l1BlobBaseFee := statedb.GetState(rcfg.L1GasPriceOracleAddress, rcfg.L1BlobBaseFeeSlot)
commitScalar := statedb.GetState(rcfg.L1GasPriceOracleAddress, rcfg.CommitScalarSlot)
blobScalar := statedb.GetState(rcfg.L1GasPriceOracleAddress, rcfg.BlobScalarSlot)
isCurie := statedb.GetState(rcfg.L1GasPriceOracleAddress, rcfg.IsCurieSlot)
if number < config.CurieBlock.Uint64() {
assert.Nil(t, baseFee, "Expected zero base fee before Curie")
// we don't have predeploys configured in this test,
// so there is no gas oracle deployed before Curie
assert.Nil(t, code)
assert.Equal(t, uint64(0), codeSize)
assert.Equal(t, common.Hash{}, keccakCodeHash)
assert.Equal(t, common.Hash{}, poseidonCodeHash)
assert.Equal(t, common.Hash{}, l1BlobBaseFee)
assert.Equal(t, common.Hash{}, commitScalar)
assert.Equal(t, common.Hash{}, blobScalar)
assert.Equal(t, common.Hash{}, isCurie)
} else {
assert.NotNil(t, baseFee, "Expected nonzero base fee after Curie")
// all gas oracle entries updated
assert.NotNil(t, code)
assert.NotEqual(t, uint64(0), codeSize)
assert.NotEqual(t, common.Hash{}, keccakCodeHash)
assert.NotEqual(t, common.Hash{}, poseidonCodeHash)
assert.NotEqual(t, common.Hash{}, l1BlobBaseFee)
assert.NotEqual(t, common.Hash{}, commitScalar)
assert.NotEqual(t, common.Hash{}, blobScalar)
assert.NotEqual(t, common.Hash{}, isCurie)
}
}
}

View file

@ -328,6 +328,9 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
if config.DAOForkSupport && config.DAOForkBlock != nil && config.DAOForkBlock.Cmp(b.header.Number) == 0 { if config.DAOForkSupport && config.DAOForkBlock != nil && config.DAOForkBlock.Cmp(b.header.Number) == 0 {
misc.ApplyDAOHardFork(statedb) misc.ApplyDAOHardFork(statedb)
} }
if config.CurieBlock != nil && config.CurieBlock.Cmp(b.header.Number) == 0 {
misc.ApplyCurieHardFork(statedb)
}
// Execute any user modifications to the block // Execute any user modifications to the block
if gen != nil { if gen != nil {
gen(i, b) gen(i, b)

View file

@ -71,7 +71,7 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c
} }
statedb.SetTxContext(tx.Hash(), i) statedb.SetTxContext(tx.Hash(), i)
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb) l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, p.config, block.Number())
if err != nil { if err != nil {
return return
} }

View file

@ -72,6 +72,10 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 { if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 {
misc.ApplyDAOHardFork(statedb) misc.ApplyDAOHardFork(statedb)
} }
// Apply Curie hard fork
if p.config.CurieBlock != nil && p.config.CurieBlock.Cmp(block.Number()) == 0 {
misc.ApplyCurieHardFork(statedb)
}
var ( var (
context = NewEVMBlockContext(header, p.bc, p.config, nil) context = NewEVMBlockContext(header, p.bc, p.config, nil)
vmenv = vm.NewEVM(context, vm.TxContext{}, statedb, p.config, cfg) vmenv = vm.NewEVM(context, vm.TxContext{}, statedb, p.config, cfg)
@ -110,7 +114,7 @@ func applyTransaction(msg *Message, config *params.ChainConfig, gp *GasPool, sta
txContext := NewEVMTxContext(msg) txContext := NewEVMTxContext(msg)
evm.Reset(txContext, statedb) evm.Reset(txContext, statedb)
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb) l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, config, blockNumber)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -1080,7 +1080,7 @@ func (p *BlobPool) validateTx(tx *types.Transaction) error {
return nil return nil
}, },
} }
if err := txpool.ValidateTransactionWithState(tx, p.signer, stateOpts); err != nil { if err := txpool.ValidateTransactionWithState(tx, p.signer, stateOpts, p.chain.Config(), p.head.Number); err != nil {
return err return err
} }
// If the transaction replaces an existing one, ensure that price bumps are // If the transaction replaces an existing one, ensure that price bumps are

View file

@ -638,7 +638,7 @@ func (pool *LegacyPool) validateTx(tx *types.Transaction, local bool) error {
return nil return nil
}, },
} }
if err := txpool.ValidateTransactionWithState(tx, pool.signer, opts); err != nil { if err := txpool.ValidateTransactionWithState(tx, pool.signer, opts, pool.chainconfig, pool.currentHead.Load().Number); err != nil {
return err return err
} }
return nil return nil
@ -759,7 +759,7 @@ func (pool *LegacyPool) add(tx *types.Transaction, local bool) (replaced bool, e
// Try to replace an existing transaction in the pending pool // Try to replace an existing transaction in the pending pool
if list := pool.pending[from]; list != nil && list.Contains(tx.Nonce()) { if list := pool.pending[from]; list != nil && list.Contains(tx.Nonce()) {
// Nonce already pending, check if required price bump is met // Nonce already pending, check if required price bump is met
inserted, old := list.Add(tx, pool.config.PriceBump) inserted, old := list.Add(tx, pool.currentState, pool.config.PriceBump, pool.chainconfig, pool.currentHead.Load().Number)
if !inserted { if !inserted {
pendingDiscardMeter.Mark(1) pendingDiscardMeter.Mark(1)
return false, txpool.ErrReplaceUnderpriced return false, txpool.ErrReplaceUnderpriced
@ -833,7 +833,7 @@ func (pool *LegacyPool) enqueueTx(hash common.Hash, tx *types.Transaction, local
if pool.queue[from] == nil { if pool.queue[from] == nil {
pool.queue[from] = newList(false) pool.queue[from] = newList(false)
} }
inserted, old := pool.queue[from].Add(tx, pool.config.PriceBump) inserted, old := pool.queue[from].Add(tx, pool.currentState, pool.config.PriceBump, pool.chainconfig, pool.currentHead.Load().Number)
if !inserted { if !inserted {
// An older transaction was better, discard this // An older transaction was better, discard this
queuedDiscardMeter.Mark(1) queuedDiscardMeter.Mark(1)
@ -887,7 +887,7 @@ func (pool *LegacyPool) promoteTx(addr common.Address, hash common.Hash, tx *typ
} }
list := pool.pending[addr] list := pool.pending[addr]
inserted, old := list.Add(tx, pool.config.PriceBump) inserted, old := list.Add(tx, pool.currentState, pool.config.PriceBump, pool.chainconfig, pool.currentHead.Load().Number)
if !inserted { if !inserted {
// An older transaction was better, discard this // An older transaction was better, discard this
pool.all.Remove(hash) pool.all.Remove(hash)

View file

@ -26,7 +26,11 @@ import (
"time" "time"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rollup/fees"
) )
// nonceHeap is a heap.Interface implementation over 64bit unsigned integers for // nonceHeap is a heap.Interface implementation over 64bit unsigned integers for
@ -298,7 +302,7 @@ func (l *list) Contains(nonce uint64) bool {
// //
// If the new transaction is accepted into the list, the lists' cost and gas // If the new transaction is accepted into the list, the lists' cost and gas
// thresholds are also potentially updated. // thresholds are also potentially updated.
func (l *list) Add(tx *types.Transaction, priceBump uint64) (bool, *types.Transaction) { func (l *list) Add(tx *types.Transaction, state *state.StateDB, priceBump uint64, chainconfig *params.ChainConfig, blockNumber *big.Int) (bool, *types.Transaction) {
// If there's an older better transaction, abort // If there's an older better transaction, abort
old := l.txs.Get(tx.Nonce()) old := l.txs.Get(tx.Nonce())
if old != nil { if old != nil {
@ -322,13 +326,24 @@ func (l *list) Add(tx *types.Transaction, priceBump uint64) (bool, *types.Transa
return false, nil return false, nil
} }
// Old is being replaced, subtract old cost // Old is being replaced, subtract old cost
// TODO: fix for L1DataFee
l.subTotalCost([]*types.Transaction{old}) l.subTotalCost([]*types.Transaction{old})
} }
l1DataFee := big.NewInt(0)
if state != nil && chainconfig != nil {
var err error
l1DataFee, err = fees.CalculateL1DataFee(tx, state, chainconfig, blockNumber)
if err != nil {
log.Error("Failed to calculate L1 data fee", "err", err, "tx", tx)
return false, nil
}
}
// Add new tx cost to totalcost // Add new tx cost to totalcost
// TODO: fix totalcost for L1DataFee for both sub and add
l.totalcost.Add(l.totalcost, tx.Cost()) l.totalcost.Add(l.totalcost, tx.Cost())
// Otherwise overwrite the old transaction with the current one // Otherwise overwrite the old transaction with the current one
l.txs.Put(tx) l.txs.Put(tx)
if cost := tx.Cost(); l.costcap.Cmp(cost) < 0 { if cost := new(big.Int).Add(tx.Cost(), l1DataFee); l.costcap.Cmp(cost) < 0 {
l.costcap = cost l.costcap = cost
} }
if gas := tx.Gas(); l.gascap < gas { if gas := tx.Gas(); l.gascap < gas {
@ -454,6 +469,7 @@ func (l *list) LastElement() *types.Transaction {
// subTotalCost subtracts the cost of the given transactions from the // subTotalCost subtracts the cost of the given transactions from the
// total cost of all transactions. // total cost of all transactions.
// TODO: fix for L1DataFee
func (l *list) subTotalCost(txs []*types.Transaction) { func (l *list) subTotalCost(txs []*types.Transaction) {
for _, tx := range txs { for _, tx := range txs {
l.totalcost.Sub(l.totalcost, tx.Cost()) l.totalcost.Sub(l.totalcost, tx.Cost())

View file

@ -21,13 +21,19 @@ import (
"math/rand" "math/rand"
"testing" "testing"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/event"
) )
// Tests that transactions can be added to strict lists and list contents and // Tests that transactions can be added to strict lists and list contents and
// nonce boundaries are correctly maintained. // nonce boundaries are correctly maintained.
func TestStrictListAdd(t *testing.T) { func TestStrictListAdd(t *testing.T) {
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
blockchain := newTestBlockChain(eip1559Config, 1000000, statedb, new(event.Feed))
// Generate a list of transactions to insert // Generate a list of transactions to insert
key, _ := crypto.GenerateKey() key, _ := crypto.GenerateKey()
@ -38,7 +44,7 @@ func TestStrictListAdd(t *testing.T) {
// Insert the transactions in a random order // Insert the transactions in a random order
list := newList(true) list := newList(true)
for _, v := range rand.Perm(len(txs)) { for _, v := range rand.Perm(len(txs)) {
list.Add(txs[v], DefaultConfig.PriceBump) list.Add(txs[v], statedb, DefaultConfig.PriceBump, blockchain.Config(), blockchain.CurrentBlock().Number)
} }
// Verify internal state // Verify internal state
if len(list.txs.items) != len(txs) { if len(list.txs.items) != len(txs) {
@ -52,6 +58,9 @@ func TestStrictListAdd(t *testing.T) {
} }
func BenchmarkListAdd(b *testing.B) { func BenchmarkListAdd(b *testing.B) {
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
blockchain := newTestBlockChain(eip1559Config, 1000000, statedb, new(event.Feed))
// Generate a list of transactions to insert // Generate a list of transactions to insert
key, _ := crypto.GenerateKey() key, _ := crypto.GenerateKey()
@ -65,7 +74,7 @@ func BenchmarkListAdd(b *testing.B) {
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
list := newList(true) list := newList(true)
for _, v := range rand.Perm(len(txs)) { for _, v := range rand.Perm(len(txs)) {
list.Add(txs[v], DefaultConfig.PriceBump) list.Add(txs[v], statedb, DefaultConfig.PriceBump, blockchain.Config(), blockchain.CurrentBlock().Number)
list.Filter(priceLimit, DefaultConfig.PriceBump) list.Filter(priceLimit, DefaultConfig.PriceBump)
} }
} }

View file

@ -197,7 +197,7 @@ type ValidationOptionsWithState struct {
// //
// This check is public to allow different transaction pools to check the stateful // This check is public to allow different transaction pools to check the stateful
// rules without duplicating code and running the risk of missed updates. // rules without duplicating code and running the risk of missed updates.
func ValidateTransactionWithState(tx *types.Transaction, signer types.Signer, opts *ValidationOptionsWithState) error { func ValidateTransactionWithState(tx *types.Transaction, signer types.Signer, opts *ValidationOptionsWithState, chainConfig *params.ChainConfig, headNumber *big.Int) error {
// Ensure the transaction adheres to nonce ordering // Ensure the transaction adheres to nonce ordering
from, err := signer.Sender(tx) // already validated (and cached), but cleaner to check from, err := signer.Sender(tx) // already validated (and cached), but cleaner to check
if err != nil { if err != nil {
@ -227,7 +227,7 @@ func ValidateTransactionWithState(tx *types.Transaction, signer types.Signer, op
// 2. Perform an additional check for L1 data fees. // 2. Perform an additional check for L1 data fees.
// Always perform the check, because it's not easy to check FeeVault here // Always perform the check, because it's not easy to check FeeVault here
// Get L1 data fee in current state // Get L1 data fee in current state
l1DataFee, err := fees.CalculateL1DataFee(tx, opts.State) l1DataFee, err := fees.CalculateL1DataFee(tx, opts.State, chainConfig, headNumber)
if err != nil { if err != nil {
return fmt.Errorf("failed to calculate L1 data fee, err: %w", err) return fmt.Errorf("failed to calculate L1 data fee, err: %w", err)
} }

View file

@ -249,7 +249,7 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block,
// Not yet the searched for transaction, execute on top of the current state // Not yet the searched for transaction, execute on top of the current state
vmenv := vm.NewEVM(context, txContext, statedb, eth.blockchain.Config(), vm.Config{}) vmenv := vm.NewEVM(context, txContext, statedb, eth.blockchain.Config(), vm.Config{})
statedb.SetTxContext(tx.Hash(), idx) statedb.SetTxContext(tx.Hash(), idx)
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb) l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, eth.blockchain.Config(), block.Number())
if err != nil { if err != nil {
return nil, vm.BlockContext{}, nil, nil, err return nil, vm.BlockContext{}, nil, nil, err
} }

View file

@ -280,7 +280,7 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed
TxIndex: i, TxIndex: i,
TxHash: tx.Hash(), TxHash: tx.Hash(),
} }
l1DataFee, err := fees.CalculateL1DataFee(tx, task.statedb) l1DataFee, err := fees.CalculateL1DataFee(tx, task.statedb, api.backend.ChainConfig(), task.block.Number())
if err != nil { if err != nil {
// though it's not a "tracing error", we still need to put it here // though it's not a "tracing error", we still need to put it here
task.results[i] = &txTraceResult{TxHash: tx.Hash(), Error: err.Error()} task.results[i] = &txTraceResult{TxHash: tx.Hash(), Error: err.Error()}
@ -546,7 +546,7 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config
vmenv = vm.NewEVM(vmctx, txContext, statedb, chainConfig, vm.Config{}) vmenv = vm.NewEVM(vmctx, txContext, statedb, chainConfig, vm.Config{})
) )
statedb.SetTxContext(tx.Hash(), i) statedb.SetTxContext(tx.Hash(), i)
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb) l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, chainConfig, block.Number())
if err != nil { if err != nil {
log.Warn("Tracing intermediate roots did not complete due to fees.CalculateL1DataFee", "txindex", i, "txhash", tx.Hash(), "err", err) log.Warn("Tracing intermediate roots did not complete due to fees.CalculateL1DataFee", "txindex", i, "txhash", tx.Hash(), "err", err)
return nil, err return nil, err
@ -627,7 +627,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
TxIndex: i, TxIndex: i,
TxHash: tx.Hash(), TxHash: tx.Hash(),
} }
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb) l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, api.backend.ChainConfig(), block.Number())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -674,7 +674,7 @@ func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, stat
TxIndex: task.index, TxIndex: task.index,
TxHash: txs[task.index].Hash(), TxHash: txs[task.index].Hash(),
} }
l1DataFee, err := fees.CalculateL1DataFee(txs[task.index], task.statedb) l1DataFee, err := fees.CalculateL1DataFee(txs[task.index], task.statedb, api.backend.ChainConfig(), block.Number())
if err != nil { if err != nil {
// though it's not a "tracing error", we still need to put it here // though it's not a "tracing error", we still need to put it here
results[task.index] = &txTraceResult{TxHash: txs[task.index].Hash(), Error: err.Error()} results[task.index] = &txTraceResult{TxHash: txs[task.index].Hash(), Error: err.Error()}
@ -707,7 +707,7 @@ txloop:
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee()) msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
statedb.SetTxContext(tx.Hash(), i) statedb.SetTxContext(tx.Hash(), i)
vmenv := vm.NewEVM(blockCtx, core.NewEVMTxContext(msg), statedb, api.backend.ChainConfig(), vm.Config{}) vmenv := vm.NewEVM(blockCtx, core.NewEVMTxContext(msg), statedb, api.backend.ChainConfig(), vm.Config{})
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb) l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, api.backend.ChainConfig(), block.Number())
if err != nil { if err != nil {
failed = err failed = err
break txloop break txloop
@ -819,7 +819,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block
// Execute the transaction and flush any traces to disk // Execute the transaction and flush any traces to disk
vmenv := vm.NewEVM(vmctx, txContext, statedb, chainConfig, vmConf) vmenv := vm.NewEVM(vmctx, txContext, statedb, chainConfig, vmConf)
statedb.SetTxContext(tx.Hash(), i) statedb.SetTxContext(tx.Hash(), i)
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb) l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, chainConfig, block.Number())
if err == nil { if err == nil {
_, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit), l1DataFee) _, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit), l1DataFee)
} }
@ -891,7 +891,7 @@ func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config *
TxIndex: int(index), TxIndex: int(index),
TxHash: hash, TxHash: hash,
} }
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb) l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, api.backend.ChainConfig(), block.Number())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -955,7 +955,7 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc
traceConfig = &config.TraceConfig traceConfig = &config.TraceConfig
} }
signer := types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time()) signer := types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time())
l1DataFee, err := fees.EstimateL1DataFeeForMessage(msg, block.BaseFee(), api.backend.ChainConfig().ChainID, signer, statedb) l1DataFee, err := fees.EstimateL1DataFeeForMessage(msg, block.BaseFee(), api.backend.ChainConfig(), signer, statedb, block.Number())
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -177,7 +177,7 @@ func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block
return msg, context, statedb, release, nil return msg, context, statedb, release, nil
} }
vmenv := vm.NewEVM(context, txContext, statedb, b.chainConfig, vm.Config{}) vmenv := vm.NewEVM(context, txContext, statedb, b.chainConfig, vm.Config{})
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb) l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, b.chainConfig, block.Number())
if err != nil { if err != nil {
return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction %#x CalculateL1DataFee failed: %v", tx.Hash(), err) return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction %#x CalculateL1DataFee failed: %v", tx.Hash(), err)
} }

View file

@ -151,7 +151,7 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("failed to prepare transaction for tracing: %v", err) t.Fatalf("failed to prepare transaction for tracing: %v", err)
} }
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb) l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, test.Genesis.Config, context.BlockNumber)
if err != nil { if err != nil {
t.Fatalf("failed to calculate l1DataFee: %v", err) t.Fatalf("failed to calculate l1DataFee: %v", err)
} }
@ -256,7 +256,7 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) {
} }
evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Tracer: tracer}) evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Tracer: tracer})
snap := statedb.Snapshot() snap := statedb.Snapshot()
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb) l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, test.Genesis.Config, context.BlockNumber)
if err != nil { if err != nil {
b.Fatalf("failed to calculate l1DataFee: %v", err) b.Fatalf("failed to calculate l1DataFee: %v", err)
} }
@ -398,7 +398,7 @@ func TestInternals(t *testing.T) {
SkipAccountChecks: false, SkipAccountChecks: false,
} }
signer := types.MakeSigner(params.MainnetChainConfig, context.BlockNumber, context.Time) signer := types.MakeSigner(params.MainnetChainConfig, context.BlockNumber, context.Time)
l1DataFee, err := fees.EstimateL1DataFeeForMessage(msg, nil, params.MainnetChainConfig.ChainID, signer, statedb) l1DataFee, err := fees.EstimateL1DataFeeForMessage(msg, nil, params.MainnetChainConfig, signer, statedb, context.BlockNumber)
if err != nil { if err != nil {
t.Fatalf("test %v: failed to estimate L1DataFee: %v", tc.name, err) t.Fatalf("test %v: failed to estimate L1DataFee: %v", tc.name, err)
} }

View file

@ -115,7 +115,7 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string
if err != nil { if err != nil {
return fmt.Errorf("failed to prepare transaction for tracing: %v", err) return fmt.Errorf("failed to prepare transaction for tracing: %v", err)
} }
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb) l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, test.Genesis.Config, context.BlockNumber)
if err != nil { if err != nil {
return fmt.Errorf("failed to calculate L1DataFee: %v", err) return fmt.Errorf("failed to calculate L1DataFee: %v", err)
} }

View file

@ -122,7 +122,7 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("failed to prepare transaction for tracing: %v", err) t.Fatalf("failed to prepare transaction for tracing: %v", err)
} }
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb) l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, test.Genesis.Config, context.BlockNumber)
if err != nil { if err != nil {
t.Fatalf("failed to calculate L1DataFee: %v", err) t.Fatalf("failed to calculate L1DataFee: %v", err)
} }

View file

@ -100,7 +100,7 @@ func BenchmarkTransactionTrace(b *testing.B) {
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
snap := statedb.Snapshot() snap := statedb.Snapshot()
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb) l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, params.AllEthashProtocolChanges, context.BlockNumber)
if err != nil { if err != nil {
b.Fatal(err) b.Fatal(err)
} }

View file

@ -35,6 +35,7 @@ import (
"github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/eth/ethconfig"
"github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rollup/rcfg"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
) )
@ -186,8 +187,22 @@ var (
) )
var genesis = &core.Genesis{ var genesis = &core.Genesis{
Config: params.AllEthashProtocolChanges, Config: params.AllEthashProtocolChanges,
Alloc: core.GenesisAlloc{testAddr: {Balance: testBalance}}, Alloc: core.GenesisAlloc{
testAddr: {Balance: testBalance},
rcfg.L1GasPriceOracleAddress: {
Balance: big.NewInt(0),
Storage: map[common.Hash]common.Hash{
rcfg.L1BaseFeeSlot: common.BigToHash(big.NewInt(10000)),
rcfg.OverheadSlot: common.BigToHash(big.NewInt(10000)),
rcfg.ScalarSlot: common.BigToHash(big.NewInt(10000)),
rcfg.L1BlobBaseFeeSlot: common.BigToHash(big.NewInt(10000)),
rcfg.CommitScalarSlot: common.BigToHash(big.NewInt(10000)),
rcfg.BlobScalarSlot: common.BigToHash(big.NewInt(10000)),
rcfg.IsCurieSlot: common.BytesToHash([]byte{1}),
},
},
},
ExtraData: []byte("test genesis"), ExtraData: []byte("test genesis"),
Timestamp: 9000, Timestamp: 9000,
BaseFee: big.NewInt(params.InitialBaseFee), BaseFee: big.NewInt(params.InitialBaseFee),

View file

@ -35,6 +35,7 @@ import (
"github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rollup/rcfg"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
) )
@ -80,8 +81,22 @@ func newTestBackend(t *testing.T) (*node.Node, []*types.Block) {
func generateTestChain() (*core.Genesis, []*types.Block) { func generateTestChain() (*core.Genesis, []*types.Block) {
genesis := &core.Genesis{ genesis := &core.Genesis{
Config: params.AllEthashProtocolChanges, Config: params.AllEthashProtocolChanges,
Alloc: core.GenesisAlloc{testAddr: {Balance: testBalance, Storage: map[common.Hash]common.Hash{testSlot: testValue}}, Alloc: core.GenesisAlloc{
testContract: {Nonce: 1, Code: []byte{0x13, 0x37}}}, testAddr: {Balance: testBalance, Storage: map[common.Hash]common.Hash{testSlot: testValue}},
testContract: {Nonce: 1, Code: []byte{0x13, 0x37}},
rcfg.L1GasPriceOracleAddress: {
Balance: big.NewInt(0),
Storage: map[common.Hash]common.Hash{
rcfg.L1BaseFeeSlot: common.BigToHash(big.NewInt(10000)),
rcfg.OverheadSlot: common.BigToHash(big.NewInt(10000)),
rcfg.ScalarSlot: common.BigToHash(big.NewInt(10000)),
rcfg.L1BlobBaseFeeSlot: common.BigToHash(big.NewInt(10000)),
rcfg.CommitScalarSlot: common.BigToHash(big.NewInt(10000)),
rcfg.BlobScalarSlot: common.BigToHash(big.NewInt(10000)),
rcfg.IsCurieSlot: common.BytesToHash([]byte{1}),
},
},
},
ExtraData: []byte("test genesis"), ExtraData: []byte("test genesis"),
Timestamp: 9000, Timestamp: 9000,
} }

View file

@ -1234,7 +1234,7 @@ func EstimateL1MsgFee(ctx context.Context, b Backend, args TransactionArgs, bloc
}() }()
signer := types.MakeSigner(config, header.Number, header.Time) signer := types.MakeSigner(config, header.Number, header.Time)
return fees.EstimateL1DataFeeForMessage(msg, header.BaseFee, config.ChainID, signer, evm.StateDB) return fees.EstimateL1DataFeeForMessage(msg, header.BaseFee, config, signer, evm.StateDB, header.Number)
} }
// executeEstimate is a helper that executes the transaction under a given gas limit and returns // executeEstimate is a helper that executes the transaction under a given gas limit and returns
@ -1729,7 +1729,7 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH
config := vm.Config{Tracer: tracer, NoBaseFee: true} config := vm.Config{Tracer: tracer, NoBaseFee: true}
vmenv, _ := b.GetEVM(ctx, msg, statedb, header, &config, nil) vmenv, _ := b.GetEVM(ctx, msg, statedb, header, &config, nil)
signer := types.MakeSigner(b.ChainConfig(), header.Number, header.Time) signer := types.MakeSigner(b.ChainConfig(), header.Number, header.Time)
l1DataFee, err := fees.EstimateL1DataFeeForMessage(msg, header.BaseFee, b.ChainConfig().ChainID, signer, statedb) l1DataFee, err := fees.EstimateL1DataFeeForMessage(msg, header.BaseFee, b.ChainConfig(), signer, statedb, header.Number)
if err != nil { if err != nil {
return nil, 0, nil, fmt.Errorf("failed to apply transaction: %v err: %v", args.toTransaction().Hash(), err) return nil, 0, nil, fmt.Errorf("failed to apply transaction: %v err: %v", args.toTransaction().Hash(), err)
} }

View file

@ -70,7 +70,7 @@ func (leth *LightEthereum) stateAtTransaction(ctx context.Context, block *types.
} }
// Not yet the searched for transaction, execute on top of the current state // Not yet the searched for transaction, execute on top of the current state
vmenv := vm.NewEVM(context, txContext, statedb, leth.blockchain.Config(), vm.Config{}) vmenv := vm.NewEVM(context, txContext, statedb, leth.blockchain.Config(), vm.Config{})
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb) l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, leth.blockchain.Config(), block.Number())
if err != nil { if err != nil {
return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err) return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err)
} }

View file

@ -219,7 +219,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain
vmenv := vm.NewEVM(context, txContext, st, config, vm.Config{NoBaseFee: true}) vmenv := vm.NewEVM(context, txContext, st, config, vm.Config{NoBaseFee: true})
gp := new(core.GasPool).AddGas(math.MaxUint64) gp := new(core.GasPool).AddGas(math.MaxUint64)
signer := types.MakeSigner(config, header.Number, header.Time) signer := types.MakeSigner(config, header.Number, header.Time)
l1DataFee, _ := fees.EstimateL1DataFeeForMessage(msg, header.BaseFee, config.ChainID, signer, st) l1DataFee, _ := fees.EstimateL1DataFeeForMessage(msg, header.BaseFee, config, signer, st, header.Number)
result, _ := core.ApplyMessage(vmenv, msg, gp, l1DataFee) result, _ := core.ApplyMessage(vmenv, msg, gp, l1DataFee)
res = append(res, result.Return()...) res = append(res, result.Return()...)
if st.Error() != nil { if st.Error() != nil {

View file

@ -72,6 +72,8 @@ type TxPool struct {
istanbul bool // Fork indicator whether we are in the istanbul stage. istanbul bool // Fork indicator whether we are in the istanbul stage.
eip2718 bool // Fork indicator whether we are in the eip2718 stage. eip2718 bool // Fork indicator whether we are in the eip2718 stage.
shanghai bool // Fork indicator whether we are in the shanghai stage. shanghai bool // Fork indicator whether we are in the shanghai stage.
currentHead *big.Int // Current blockchain head
} }
// TxRelayBackend provides an interface to the mechanism that forwards transactions to the // TxRelayBackend provides an interface to the mechanism that forwards transactions to the
@ -320,6 +322,8 @@ func (pool *TxPool) setNewHead(head *types.Header) {
pool.istanbul = pool.config.IsIstanbul(next) pool.istanbul = pool.config.IsIstanbul(next)
pool.eip2718 = pool.config.IsBerlin(next) pool.eip2718 = pool.config.IsBerlin(next)
pool.shanghai = pool.config.IsShanghai(next, uint64(time.Now().Unix())) pool.shanghai = pool.config.IsShanghai(next, uint64(time.Now().Unix()))
pool.currentHead = next
} }
// Stop stops the light transaction pool // Stop stops the light transaction pool
@ -389,7 +393,7 @@ func (pool *TxPool) validateTx(ctx context.Context, tx *types.Transaction) error
// 2. If FeeVault is enabled, perform an additional check for L1 data fees. // 2. If FeeVault is enabled, perform an additional check for L1 data fees.
if pool.config.Scroll.FeeVaultEnabled() { if pool.config.Scroll.FeeVaultEnabled() {
// Get L1 data fee in current state // Get L1 data fee in current state
l1DataFee, err := fees.CalculateL1DataFee(tx, currentState) l1DataFee, err := fees.CalculateL1DataFee(tx, currentState, pool.config, pool.currentHead)
if err != nil { if err != nil {
return fmt.Errorf("failed to calculate L1 data fee, err: %w", err) return fmt.Errorf("failed to calculate L1 data fee, err: %w", err)
} }

View file

@ -26,6 +26,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/consensus/misc"
"github.com/ethereum/go-ethereum/consensus/misc/eip1559" "github.com/ethereum/go-ethereum/consensus/misc/eip1559"
"github.com/ethereum/go-ethereum/consensus/misc/eip4844" "github.com/ethereum/go-ethereum/consensus/misc/eip4844"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
@ -1384,6 +1385,9 @@ func (w *worker) prepareWork(genParams *generateParams) (*environment, error) {
log.Error("Failed to create sealing context", "err", err) log.Error("Failed to create sealing context", "err", err)
return nil, err return nil, err
} }
if w.chainConfig.CurieBlock != nil && w.chainConfig.CurieBlock.Cmp(header.Number) == 0 {
misc.ApplyCurieHardFork(env.state)
}
if header.ParentBeaconRoot != nil { if header.ParentBeaconRoot != nil {
context := core.NewEVMBlockContext(header, w.chain, w.chainConfig, nil) context := core.NewEVMBlockContext(header, w.chain, w.chainConfig, nil)
vmenv := vm.NewEVM(context, vm.TxContext{}, env.state, w.chainConfig, vm.Config{}) vmenv := vm.NewEVM(context, vm.TxContext{}, env.state, w.chainConfig, vm.Config{})
@ -1571,35 +1575,45 @@ func (w *worker) commitWork(interrupt *atomic.Int32, timestamp int64) {
if err != nil { if err != nil {
return return
} }
// Fill pending transactions from the txpool into the block.
err = w.fillTransactions(interrupt, work)
switch {
case err == nil:
// The entire block is filled, decrease resubmit interval in case
// of current interval is larger than the user-specified one.
w.resubmitAdjustCh <- &intervalAdjust{inc: false}
case errors.Is(err, errBlockInterruptedByRecommit): noTxs := false
// Notify resubmit loop to increase resubmitting interval if the // zkEVM requirement: Curie transition block has 0 transactions
// interruption is due to frequent commits. if w.chainConfig.CurieBlock != nil && w.chainConfig.CurieBlock.Cmp(work.header.Number) == 0 {
gaslimit := work.header.GasLimit noTxs = true
ratio := float64(gaslimit-work.gasPool.Gas()) / float64(gaslimit)
if ratio < 0.1 {
ratio = 0.1
}
w.resubmitAdjustCh <- &intervalAdjust{
ratio: ratio,
inc: true,
}
case errors.Is(err, errBlockInterruptedByNewHead):
// If the block building is interrupted by newhead event, discard it
// totally. Committing the interrupted block introduces unnecessary
// delay, and possibly causes miner to mine on the previous head,
// which could result in higher uncle rate.
work.discard()
return
} }
if !noTxs {
// Fill pending transactions from the txpool into the block.
err = w.fillTransactions(interrupt, work)
switch {
case err == nil:
// The entire block is filled, decrease resubmit interval in case
// of current interval is larger than the user-specified one.
w.resubmitAdjustCh <- &intervalAdjust{inc: false}
case errors.Is(err, errBlockInterruptedByRecommit):
// Notify resubmit loop to increase resubmitting interval if the
// interruption is due to frequent commits.
gaslimit := work.header.GasLimit
ratio := float64(gaslimit-work.gasPool.Gas()) / float64(gaslimit)
if ratio < 0.1 {
ratio = 0.1
}
w.resubmitAdjustCh <- &intervalAdjust{
ratio: ratio,
inc: true,
}
case errors.Is(err, errBlockInterruptedByNewHead):
// If the block building is interrupted by newhead event, discard it
// totally. Committing the interrupted block introduces unnecessary
// delay, and possibly causes miner to mine on the previous head,
// which could result in higher uncle rate.
work.discard()
return
}
}
// Submit the generated block for consensus sealing. // Submit the generated block for consensus sealing.
w.commit(work.copy(), w.fullTaskHook, true, start) w.commit(work.copy(), w.fullTaskHook, true, start)

View file

@ -2,6 +2,7 @@ package fees
import ( import (
"bytes" "bytes"
"math"
"math/big" "math/big"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
@ -43,25 +44,42 @@ type StateDB interface {
GetBalance(addr common.Address) *big.Int GetBalance(addr common.Address) *big.Int
} }
func EstimateL1DataFeeForMessage(msg Message, baseFee, chainID *big.Int, signer types.Signer, state StateDB) (*big.Int, error) { type gpoState struct {
l1BaseFee *big.Int
overhead *big.Int
scalar *big.Int
l1BlobBaseFee *big.Int
commitScalar *big.Int
blobScalar *big.Int
}
func EstimateL1DataFeeForMessage(msg Message, baseFee *big.Int, config *params.ChainConfig, signer types.Signer, state StateDB, blockNumber *big.Int) (*big.Int, error) {
if msg.GetIsL1MessageTx() { if msg.GetIsL1MessageTx() {
return big.NewInt(0), nil return big.NewInt(0), nil
} }
unsigned := asUnsignedTx(msg, baseFee, chainID) unsigned := asUnsignedTx(msg, baseFee, config.ChainID)
// with v=1 // with v=1
tx, err := unsigned.WithSignature(signer, append(bytes.Repeat([]byte{0xff}, crypto.SignatureLength-1), 0x01)) tx, err := unsigned.WithSignature(signer, append(bytes.Repeat([]byte{0xff}, crypto.SignatureLength-1), 0x01))
if err != nil { if err != nil {
return nil, err return nil, err
} }
raw, err := rlpEncode(tx) raw, err := tx.MarshalBinary()
if err != nil { if err != nil {
return nil, err return nil, err
} }
l1BaseFee, overhead, scalar := readGPOStorageSlots(rcfg.L1GasPriceOracleAddress, state) gpoState := readGPOStorageSlots(rcfg.L1GasPriceOracleAddress, state)
l1DataFee := calculateEncodedL1DataFee(raw, overhead, l1BaseFee, scalar)
var l1DataFee *big.Int
if !config.IsCurie(blockNumber) {
l1DataFee = calculateEncodedL1DataFee(raw, gpoState.overhead, gpoState.l1BaseFee, gpoState.scalar)
} else {
l1DataFee = calculateEncodedL1DataFeeCurie(raw, gpoState.l1BaseFee, gpoState.l1BlobBaseFee, gpoState.commitScalar, gpoState.blobScalar)
}
return l1DataFee, nil return l1DataFee, nil
} }
@ -116,35 +134,46 @@ func asUnsignedDynamicTx(msg Message, chainID *big.Int) *types.Transaction {
}) })
} }
// rlpEncode RLP encodes the transaction into bytes func readGPOStorageSlots(addr common.Address, state StateDB) gpoState {
func rlpEncode(tx *types.Transaction) ([]byte, error) { var gpoState gpoState
raw := new(bytes.Buffer) gpoState.l1BaseFee = state.GetState(addr, rcfg.L1BaseFeeSlot).Big()
if err := tx.EncodeRLP(raw); err != nil { gpoState.overhead = state.GetState(addr, rcfg.OverheadSlot).Big()
return nil, err gpoState.scalar = state.GetState(addr, rcfg.ScalarSlot).Big()
} gpoState.l1BlobBaseFee = state.GetState(addr, rcfg.L1BlobBaseFeeSlot).Big()
gpoState.commitScalar = state.GetState(addr, rcfg.CommitScalarSlot).Big()
return raw.Bytes(), nil gpoState.blobScalar = state.GetState(addr, rcfg.BlobScalarSlot).Big()
} return gpoState
func readGPOStorageSlots(addr common.Address, state StateDB) (*big.Int, *big.Int, *big.Int) {
l1BaseFee := state.GetState(addr, rcfg.L1BaseFeeSlot)
overhead := state.GetState(addr, rcfg.OverheadSlot)
scalar := state.GetState(addr, rcfg.ScalarSlot)
return l1BaseFee.Big(), overhead.Big(), scalar.Big()
} }
// calculateEncodedL1DataFee computes the L1 fee for an RLP-encoded tx // calculateEncodedL1DataFee computes the L1 fee for an RLP-encoded tx
func calculateEncodedL1DataFee(data []byte, overhead, l1GasPrice *big.Int, scalar *big.Int) *big.Int { func calculateEncodedL1DataFee(data []byte, overhead, l1BaseFee *big.Int, scalar *big.Int) *big.Int {
l1GasUsed := CalculateL1GasUsed(data, overhead) l1GasUsed := calculateL1GasUsed(data, overhead)
l1DataFee := new(big.Int).Mul(l1GasUsed, l1GasPrice) l1DataFee := new(big.Int).Mul(l1GasUsed, l1BaseFee)
return mulAndScale(l1DataFee, scalar, rcfg.Precision) return mulAndScale(l1DataFee, scalar, rcfg.Precision)
} }
// CalculateL1GasUsed computes the L1 gas used based on the calldata and // calculateEncodedL1DataFeeCurie computes the L1 fee for an RLP-encoded tx, post Curie
func calculateEncodedL1DataFeeCurie(data []byte, l1BaseFee *big.Int, l1BlobBaseFee *big.Int, commitScalar *big.Int, blobScalar *big.Int) *big.Int {
// calldata component of commit fees (calldata gas + execution)
calldataGas := new(big.Int).Mul(commitScalar, l1BaseFee)
// blob component of commit fees
blobGas := big.NewInt(int64(len(data)))
blobGas = new(big.Int).Mul(blobGas, l1BlobBaseFee)
blobGas = new(big.Int).Mul(blobGas, blobScalar)
// combined
l1DataFee := new(big.Int).Add(calldataGas, blobGas)
l1DataFee = new(big.Int).Quo(l1DataFee, rcfg.Precision)
return l1DataFee
}
// calculateL1GasUsed computes the L1 gas used based on the calldata and
// constant sized overhead. The overhead can be decreased as the cost of the // constant sized overhead. The overhead can be decreased as the cost of the
// batch submission goes down via contract optimizations. This will not overflow // batch submission goes down via contract optimizations. This will not overflow
// under standard network conditions. // under standard network conditions.
func CalculateL1GasUsed(data []byte, overhead *big.Int) *big.Int { func calculateL1GasUsed(data []byte, overhead *big.Int) *big.Int {
zeroes, ones := zeroesAndOnes(data) zeroes, ones := zeroesAndOnes(data)
zeroesGas := zeroes * params.TxDataZeroGas zeroesGas := zeroes * params.TxDataZeroGas
onesGas := (ones + txExtraDataBytes) * params.TxDataNonZeroGasEIP2028 onesGas := (ones + txExtraDataBytes) * params.TxDataNonZeroGasEIP2028
@ -173,18 +202,32 @@ func mulAndScale(x *big.Int, y *big.Int, precision *big.Int) *big.Int {
return new(big.Int).Quo(z, precision) return new(big.Int).Quo(z, precision)
} }
func CalculateL1DataFee(tx *types.Transaction, state StateDB) (*big.Int, error) { func CalculateL1DataFee(tx *types.Transaction, state StateDB, config *params.ChainConfig, blockNumber *big.Int) (*big.Int, error) {
if tx.IsL1MessageTx() { if tx.IsL1MessageTx() {
return big.NewInt(0), nil return big.NewInt(0), nil
} }
raw, err := rlpEncode(tx) raw, err := tx.MarshalBinary()
if err != nil { if err != nil {
return nil, err return nil, err
} }
l1BaseFee, overhead, scalar := readGPOStorageSlots(rcfg.L1GasPriceOracleAddress, state) gpoState := readGPOStorageSlots(rcfg.L1GasPriceOracleAddress, state)
l1DataFee := calculateEncodedL1DataFee(raw, overhead, l1BaseFee, scalar)
var l1DataFee *big.Int
if !config.IsCurie(blockNumber) {
l1DataFee = calculateEncodedL1DataFee(raw, gpoState.overhead, gpoState.l1BaseFee, gpoState.scalar)
} else {
l1DataFee = calculateEncodedL1DataFeeCurie(raw, gpoState.l1BaseFee, gpoState.l1BlobBaseFee, gpoState.commitScalar, gpoState.blobScalar)
}
// ensure l1DataFee fits into uint64 for circuit compatibility
// (note: in practice this value should never be this big)
if !l1DataFee.IsUint64() {
l1DataFee.SetUint64(math.MaxUint64)
}
return l1DataFee, nil return l1DataFee, nil
} }

View file

@ -7,14 +7,27 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func TestCalculateEncodedL1DataFee(t *testing.T) { func TestL1DataFeeBeforeCurie(t *testing.T) {
l1BaseFee := new(big.Int).SetUint64(15000000) l1BaseFee := new(big.Int).SetUint64(15000000)
data := []byte{0, 10, 1, 0}
overhead := new(big.Int).SetUint64(100) overhead := new(big.Int).SetUint64(100)
scalar := new(big.Int).SetUint64(10) scalar := new(big.Int).SetUint64(10)
expected := new(big.Int).SetUint64(184) // 184.2 data := []byte{0, 10, 1, 0}
expected := new(big.Int).SetUint64(30) // 30.6
actual := calculateEncodedL1DataFee(data, overhead, l1BaseFee, scalar) actual := calculateEncodedL1DataFee(data, overhead, l1BaseFee, scalar)
assert.Equal(t, expected, actual) assert.Equal(t, expected, actual)
} }
func TestL1DataFeeAfterCurie(t *testing.T) {
l1BaseFee := new(big.Int).SetUint64(1500000000)
l1BlobBaseFee := new(big.Int).SetUint64(150000000)
commitScalar := new(big.Int).SetUint64(10)
blobScalar := new(big.Int).SetUint64(10)
data := []byte{0, 10, 1, 0}
expected := new(big.Int).SetUint64(21)
actual := calculateEncodedL1DataFeeCurie(data, l1BaseFee, l1BlobBaseFee, commitScalar, blobScalar)
assert.Equal(t, expected, actual)
}

File diff suppressed because one or more lines are too long

View file

@ -220,7 +220,7 @@ func (env *TraceEnv) GetBlockTrace(block *types.Block) (*types.BlockTrace, error
msg, _ := core.TransactionToMessage(tx, env.signer, block.BaseFee()) msg, _ := core.TransactionToMessage(tx, env.signer, block.BaseFee())
env.state.SetTxContext(tx.Hash(), i) env.state.SetTxContext(tx.Hash(), i)
vmenv := vm.NewEVM(env.blockCtx, core.NewEVMTxContext(msg), env.state, env.chainConfig, vm.Config{}) vmenv := vm.NewEVM(env.blockCtx, core.NewEVMTxContext(msg), env.state, env.chainConfig, vm.Config{})
l1DataFee, err := fees.CalculateL1DataFee(tx, env.state) l1DataFee, err := fees.CalculateL1DataFee(tx, env.state, env.chainConfig, block.Number())
if err != nil { if err != nil {
failed = err failed = err
break break
@ -330,7 +330,7 @@ func (env *TraceEnv) getTxResult(state *state.StateDB, index int, block *types.B
state.SetTxContext(txctx.TxHash, txctx.TxIndex) state.SetTxContext(txctx.TxHash, txctx.TxIndex)
// Computes the new state by applying the given message. // Computes the new state by applying the given message.
l1DataFee, err := fees.CalculateL1DataFee(tx, state) l1DataFee, err := fees.CalculateL1DataFee(tx, state, env.chainConfig, block.Number())
if err != nil { if err != nil {
return err return err
} }
@ -515,6 +515,10 @@ func (env *TraceEnv) fillBlockTrace(block *types.Block) (*types.BlockTrace, erro
rcfg.L1BaseFeeSlot, rcfg.L1BaseFeeSlot,
rcfg.OverheadSlot, rcfg.OverheadSlot,
rcfg.ScalarSlot, rcfg.ScalarSlot,
rcfg.L1BlobBaseFeeSlot,
rcfg.CommitScalarSlot,
rcfg.BlobScalarSlot,
rcfg.IsCurieSlot,
}, },
} }

View file

@ -290,7 +290,7 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh
snapshot := statedb.Snapshot() snapshot := statedb.Snapshot()
gaspool := new(core.GasPool) gaspool := new(core.GasPool)
gaspool.AddGas(block.GasLimit()) gaspool.AddGas(block.GasLimit())
l1DataFee, err := fees.CalculateL1DataFee(&ttx, statedb) l1DataFee, err := fees.CalculateL1DataFee(&ttx, statedb, config, block.Number())
if err != nil { if err != nil {
return nil, nil, nil, common.Hash{}, err return nil, nil, nil, common.Hash{}, err
} }