Skip to content

Commit

Permalink
sync l1datafee change for curie (#888)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
0xmountaintop authored Jul 9, 2024
1 parent 5e255cf commit f777318
Show file tree
Hide file tree
Showing 31 changed files with 367 additions and 103 deletions.
2 changes: 1 addition & 1 deletion accounts/abi/bind/backends/simulated.go
Original file line number Diff line number Diff line change
Expand Up @@ -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})
gasPool := new(core.GasPool).AddGas(math.MaxUint64)
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 {
return nil, err
}
Expand Down
6 changes: 5 additions & 1 deletion cmd/evm/internal/t8ntool/execution.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
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 {
evm := vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vmConfig)
core.ProcessBeaconBlockRoot(*beaconRoot, evm, statedb)
Expand Down Expand Up @@ -221,7 +225,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
)
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 {
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()})
Expand Down
23 changes: 23 additions & 0 deletions consensus/misc/curie.go
Original file line number Diff line number Diff line change
@@ -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))
}
78 changes: 78 additions & 0 deletions core/blockchain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package core

import (
"encoding/json"
"errors"
"fmt"
"math/big"
Expand All @@ -39,7 +40,9 @@ import (
"github.com/ethereum/go-ethereum/eth/tracers/logger"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rollup/rcfg"
"github.com/ethereum/go-ethereum/trie"
"github.com/stretchr/testify/assert"
)

// So we can deterministically seed different blockchains
Expand Down Expand Up @@ -4716,3 +4719,78 @@ func TestEIP3651(t *testing.T) {
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)
}
}
}
3 changes: 3 additions & 0 deletions core/chain_makers.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
misc.ApplyDAOHardFork(statedb)
}
if config.CurieBlock != nil && config.CurieBlock.Cmp(b.header.Number) == 0 {
misc.ApplyCurieHardFork(statedb)
}
// Execute any user modifications to the block
if gen != nil {
gen(i, b)
Expand Down
2 changes: 1 addition & 1 deletion core/state_prefetcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c
}
statedb.SetTxContext(tx.Hash(), i)

l1DataFee, err := fees.CalculateL1DataFee(tx, statedb)
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, p.config, block.Number())
if err != nil {
return
}
Expand Down
6 changes: 5 additions & 1 deletion core/state_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
misc.ApplyDAOHardFork(statedb)
}
// Apply Curie hard fork
if p.config.CurieBlock != nil && p.config.CurieBlock.Cmp(block.Number()) == 0 {
misc.ApplyCurieHardFork(statedb)
}
var (
context = NewEVMBlockContext(header, p.bc, p.config, nil)
vmenv = vm.NewEVM(context, vm.TxContext{}, statedb, p.config, cfg)
Expand Down Expand Up @@ -110,7 +114,7 @@ func applyTransaction(msg *Message, config *params.ChainConfig, gp *GasPool, sta
txContext := NewEVMTxContext(msg)
evm.Reset(txContext, statedb)

l1DataFee, err := fees.CalculateL1DataFee(tx, statedb)
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, config, blockNumber)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion core/txpool/blobpool/blobpool.go
Original file line number Diff line number Diff line change
Expand Up @@ -1080,7 +1080,7 @@ func (p *BlobPool) validateTx(tx *types.Transaction) error {
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
}
// If the transaction replaces an existing one, ensure that price bumps are
Expand Down
8 changes: 4 additions & 4 deletions core/txpool/legacypool/legacypool.go
Original file line number Diff line number Diff line change
Expand Up @@ -638,7 +638,7 @@ func (pool *LegacyPool) validateTx(tx *types.Transaction, local bool) error {
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 nil
Expand Down Expand Up @@ -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
if list := pool.pending[from]; list != nil && list.Contains(tx.Nonce()) {
// 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 {
pendingDiscardMeter.Mark(1)
return false, txpool.ErrReplaceUnderpriced
Expand Down Expand Up @@ -833,7 +833,7 @@ func (pool *LegacyPool) enqueueTx(hash common.Hash, tx *types.Transaction, local
if pool.queue[from] == nil {
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 {
// An older transaction was better, discard this
queuedDiscardMeter.Mark(1)
Expand Down Expand Up @@ -887,7 +887,7 @@ func (pool *LegacyPool) promoteTx(addr common.Address, hash common.Hash, tx *typ
}
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 {
// An older transaction was better, discard this
pool.all.Remove(hash)
Expand Down
20 changes: 18 additions & 2 deletions core/txpool/legacypool/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,11 @@ import (
"time"

"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/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
Expand Down Expand Up @@ -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
// 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
old := l.txs.Get(tx.Nonce())
if old != nil {
Expand All @@ -322,13 +326,24 @@ func (l *list) Add(tx *types.Transaction, priceBump uint64) (bool, *types.Transa
return false, nil
}
// Old is being replaced, subtract old cost
// TODO: fix for L1DataFee
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
// TODO: fix totalcost for L1DataFee for both sub and add
l.totalcost.Add(l.totalcost, tx.Cost())
// Otherwise overwrite the old transaction with the current one
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
}
if gas := tx.Gas(); l.gascap < gas {
Expand Down Expand Up @@ -454,6 +469,7 @@ func (l *list) LastElement() *types.Transaction {

// subTotalCost subtracts the cost of the given transactions from the
// total cost of all transactions.
// TODO: fix for L1DataFee
func (l *list) subTotalCost(txs []*types.Transaction) {
for _, tx := range txs {
l.totalcost.Sub(l.totalcost, tx.Cost())
Expand Down
13 changes: 11 additions & 2 deletions core/txpool/legacypool/list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,19 @@ import (
"math/rand"
"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/crypto"
"github.com/ethereum/go-ethereum/event"
)

// Tests that transactions can be added to strict lists and list contents and
// nonce boundaries are correctly maintained.
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
key, _ := crypto.GenerateKey()

Expand All @@ -38,7 +44,7 @@ func TestStrictListAdd(t *testing.T) {
// Insert the transactions in a random order
list := newList(true)
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
if len(list.txs.items) != len(txs) {
Expand All @@ -52,6 +58,9 @@ func TestStrictListAdd(t *testing.T) {
}

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
key, _ := crypto.GenerateKey()

Expand All @@ -65,7 +74,7 @@ func BenchmarkListAdd(b *testing.B) {
for i := 0; i < b.N; i++ {
list := newList(true)
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)
}
}
Expand Down
4 changes: 2 additions & 2 deletions core/txpool/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ type ValidationOptionsWithState struct {
//
// This check is public to allow different transaction pools to check the stateful
// 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
from, err := signer.Sender(tx) // already validated (and cached), but cleaner to check
if err != nil {
Expand Down Expand Up @@ -227,7 +227,7 @@ func ValidateTransactionWithState(tx *types.Transaction, signer types.Signer, op
// 2. Perform an additional check for L1 data fees.
// Always perform the check, because it's not easy to check FeeVault here
// 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 {
return fmt.Errorf("failed to calculate L1 data fee, err: %w", err)
}
Expand Down
2 changes: 1 addition & 1 deletion eth/state_accessor.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
vmenv := vm.NewEVM(context, txContext, statedb, eth.blockchain.Config(), vm.Config{})
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 {
return nil, vm.BlockContext{}, nil, nil, err
}
Expand Down
Loading

0 comments on commit f777318

Please sign in to comment.