feat: check basefee in Curie (#770)

* add consensus/misc/eip1559/eip1559_scroll.go

* update core/chain_makers.go

* add `fees.GetL1BaseFee`

* update eth/gasprice/feehistory.go

* fix internal/ethapi/api.go & eth/filters/api.go

* update graphql/graphql.go

* update miner/worker.go

* update txpool

* fix api_backend

* fix Curie

* update core/state_transition.go

* update internal/ethapi/transaction_args.go

* fix cmd/evm/internal/t8ntool/transition.go

* update core/state_processor_test.go

* update core/txpool/blobpool/blobpool_test.go

* fix internal/ethapi/api_test.go

* update eth/gasprice/gasprice_test.go

* update internal/ethapi/transaction_args_test.go

* update accounts/abi/bind/backends/simulated.go

* update accounts/abi/bind/base.go
This commit is contained in:
HAOYUatHZ 2024-05-28 08:37:13 +08:00 committed by GitHub
parent 34bf14978e
commit e5171495e1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
31 changed files with 301 additions and 81 deletions

View file

@ -646,7 +646,7 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM
if call.GasPrice != nil && (call.GasFeeCap != nil || call.GasTipCap != nil) { if call.GasPrice != nil && (call.GasFeeCap != nil || call.GasTipCap != nil) {
return nil, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified") return nil, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
} }
if !b.blockchain.Config().IsLondon(header.Number) { if !b.blockchain.Config().IsCurie(header.Number) {
// If there's no basefee, then it must be a non-1559 execution // If there's no basefee, then it must be a non-1559 execution
if call.GasPrice == nil { if call.GasPrice == nil {
call.GasPrice = new(big.Int) call.GasPrice = new(big.Int)
@ -668,7 +668,11 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM
// Backfill the legacy gasPrice for EVM execution, unless we're all zeroes // Backfill the legacy gasPrice for EVM execution, unless we're all zeroes
call.GasPrice = new(big.Int) call.GasPrice = new(big.Int)
if call.GasFeeCap.BitLen() > 0 || call.GasTipCap.BitLen() > 0 { if call.GasFeeCap.BitLen() > 0 || call.GasTipCap.BitLen() > 0 {
call.GasPrice = math.BigMin(new(big.Int).Add(call.GasTipCap, header.BaseFee), call.GasFeeCap) if header.BaseFee != nil {
call.GasPrice = math.BigMin(new(big.Int).Add(call.GasTipCap, header.BaseFee), call.GasFeeCap)
} else {
call.GasPrice = math.BigMin(call.GasTipCap, call.GasFeeCap)
}
} }
} }
} }
@ -980,3 +984,7 @@ func nullSubscription() event.Subscription {
return nil return nil
}) })
} }
func (fb *filterBackend) StateAt(root common.Hash) (*state.StateDB, error) {
return fb.bc.StateAt(root)
}

View file

@ -277,10 +277,14 @@ func (c *BoundContract) createDynamicTx(opts *TransactOpts, contract *common.Add
// Estimate FeeCap // Estimate FeeCap
gasFeeCap := opts.GasFeeCap gasFeeCap := opts.GasFeeCap
if gasFeeCap == nil { if gasFeeCap == nil {
gasFeeCap = new(big.Int).Add( if head.BaseFee != nil {
gasTipCap, gasFeeCap = new(big.Int).Add(
new(big.Int).Mul(head.BaseFee, big.NewInt(basefeeWiggleMultiplier)), gasTipCap,
) new(big.Int).Mul(head.BaseFee, big.NewInt(basefeeWiggleMultiplier)),
)
} else {
gasFeeCap = new(big.Int).Set(gasTipCap)
}
} }
if gasFeeCap.Cmp(gasTipCap) < 0 { if gasFeeCap.Cmp(gasTipCap) < 0 {
return nil, fmt.Errorf("maxFeePerGas (%v) < maxPriorityFeePerGas (%v)", gasFeeCap, gasTipCap) return nil, fmt.Errorf("maxFeePerGas (%v) < maxPriorityFeePerGas (%v)", gasFeeCap, gasTipCap)
@ -313,7 +317,7 @@ func (c *BoundContract) createDynamicTx(opts *TransactOpts, contract *common.Add
func (c *BoundContract) createLegacyTx(opts *TransactOpts, contract *common.Address, input []byte) (*types.Transaction, error) { func (c *BoundContract) createLegacyTx(opts *TransactOpts, contract *common.Address, input []byte) (*types.Transaction, error) {
if opts.GasFeeCap != nil || opts.GasTipCap != nil { if opts.GasFeeCap != nil || opts.GasTipCap != nil {
return nil, errors.New("maxFeePerGas or maxPriorityFeePerGas specified but london is not active yet") return nil, errors.New("maxFeePerGas or maxPriorityFeePerGas specified but curie is not active yet")
} }
// Normalize value // Normalize value
value := opts.Value value := opts.Value

View file

@ -81,6 +81,8 @@ type input struct {
Env *stEnv `json:"env,omitempty"` Env *stEnv `json:"env,omitempty"`
Txs []*txWithKey `json:"txs,omitempty"` Txs []*txWithKey `json:"txs,omitempty"`
TxRlp string `json:"txsRlp,omitempty"` TxRlp string `json:"txsRlp,omitempty"`
ParentL1BaseFee *big.Int `json:"parentL1BaseFee,omitempty"`
} }
func Transition(ctx *cli.Context) error { func Transition(ctx *cli.Context) error {
@ -195,7 +197,7 @@ func Transition(ctx *cli.Context) error {
if txs, err = loadTransactions(txStr, inputData, prestate.Env, chainConfig); err != nil { if txs, err = loadTransactions(txStr, inputData, prestate.Env, chainConfig); err != nil {
return err return err
} }
if err := applyLondonChecks(&prestate.Env, chainConfig); err != nil { if err := applyCurieChecks(&prestate.Env, chainConfig, inputData.ParentL1BaseFee); err != nil {
return err return err
} }
if err := applyShanghaiChecks(&prestate.Env, chainConfig); err != nil { if err := applyShanghaiChecks(&prestate.Env, chainConfig); err != nil {
@ -338,8 +340,8 @@ func loadTransactions(txStr string, inputData *input, env stEnv, chainConfig *pa
return signUnsignedTransactions(txsWithKeys, signer) return signUnsignedTransactions(txsWithKeys, signer)
} }
func applyLondonChecks(env *stEnv, chainConfig *params.ChainConfig) error { func applyCurieChecks(env *stEnv, chainConfig *params.ChainConfig, parentL1BaseFee *big.Int) error {
if !chainConfig.IsLondon(big.NewInt(int64(env.Number))) { if !chainConfig.IsCurie(big.NewInt(int64(env.Number))) {
return nil return nil
} }
// Sanity check, to not `panic` in state_transition // Sanity check, to not `panic` in state_transition
@ -350,12 +352,15 @@ func applyLondonChecks(env *stEnv, chainConfig *params.ChainConfig) error {
if env.ParentBaseFee == nil || env.Number == 0 { if env.ParentBaseFee == nil || env.Number == 0 {
return NewError(ErrorConfig, errors.New("EIP-1559 config but missing 'currentBaseFee' in env section")) return NewError(ErrorConfig, errors.New("EIP-1559 config but missing 'currentBaseFee' in env section"))
} }
if parentL1BaseFee == nil {
return errors.New("EIP-1559 config but missing 'parentL1BaseFee' for calculating basefee")
}
env.BaseFee = eip1559.CalcBaseFee(chainConfig, &types.Header{ env.BaseFee = eip1559.CalcBaseFee(chainConfig, &types.Header{
Number: new(big.Int).SetUint64(env.Number - 1), Number: new(big.Int).SetUint64(env.Number - 1),
BaseFee: env.ParentBaseFee, BaseFee: env.ParentBaseFee,
GasUsed: env.ParentGasUsed, GasUsed: env.ParentGasUsed,
GasLimit: env.ParentGasLimit, GasLimit: env.ParentGasLimit,
}) }, parentL1BaseFee)
return nil return nil
} }

View file

@ -336,7 +336,7 @@ func (c *Clique) verifyCascadingFields(chain consensus.ChainHeaderReader, header
if header.GasUsed > header.GasLimit { if header.GasUsed > header.GasLimit {
return fmt.Errorf("invalid gasUsed: have %d, gasLimit %d", header.GasUsed, header.GasLimit) return fmt.Errorf("invalid gasUsed: have %d, gasLimit %d", header.GasUsed, header.GasLimit)
} }
if !chain.Config().IsLondon(header.Number) { if !chain.Config().IsCurie(header.Number) {
// Verify BaseFee not present before EIP-1559 fork. // Verify BaseFee not present before EIP-1559 fork.
if header.BaseFee != nil { if header.BaseFee != nil {
return fmt.Errorf("invalid baseFee before fork: have %d, want <nil>", header.BaseFee) return fmt.Errorf("invalid baseFee before fork: have %d, want <nil>", header.BaseFee)

View file

@ -247,7 +247,7 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainHeaderReader, header, pa
return fmt.Errorf("invalid gasUsed: have %d, gasLimit %d", header.GasUsed, header.GasLimit) return fmt.Errorf("invalid gasUsed: have %d, gasLimit %d", header.GasUsed, header.GasLimit)
} }
// Verify the block's gas usage and (if applicable) verify the base fee. // Verify the block's gas usage and (if applicable) verify the base fee.
if !chain.Config().IsLondon(header.Number) { if !chain.Config().IsCurie(header.Number) {
// Verify BaseFee not present before EIP-1559 fork. // Verify BaseFee not present before EIP-1559 fork.
if header.BaseFee != nil { if header.BaseFee != nil {
return fmt.Errorf("invalid baseFee before fork: have %d, expected 'nil'", header.BaseFee) return fmt.Errorf("invalid baseFee before fork: have %d, expected 'nil'", header.BaseFee)

View file

@ -16,6 +16,8 @@
package eip1559 package eip1559
/*
import ( import (
"errors" "errors"
"fmt" "fmt"
@ -93,3 +95,5 @@ func CalcBaseFee(config *params.ChainConfig, parent *types.Header) *big.Int {
return math.BigMax(baseFee, common.Big0) return math.BigMax(baseFee, common.Big0)
} }
} }
*/

View file

@ -0,0 +1,73 @@
// Copyright 2021 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package eip1559
import (
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/consensus/misc"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params"
)
// Protocol-enforced maximum L2 base fee.
// We would only go above this if L1 base fee hits 700 Gwei.
const MaximumL2BaseFee = 10000000000
// VerifyEIP1559Header verifies some header attributes which were changed in EIP-1559,
// - gas limit check
// - basefee check
func VerifyEIP1559Header(config *params.ChainConfig, parent, header *types.Header) error {
// Verify that the gas limit remains within allowed bounds
if err := misc.VerifyGaslimit(parent.GasLimit, header.GasLimit); err != nil {
return err
}
// Verify the header is not malformed
if header.BaseFee == nil {
return fmt.Errorf("header is missing baseFee")
}
// note: we do not verify L2 base fee, the sequencer has the
// right to set any base fee below the maximum. L2 base fee
// is not subject to L2 consensus or zk verification.
if header.BaseFee.Cmp(big.NewInt(MaximumL2BaseFee)) > 0 {
return fmt.Errorf("invalid baseFee: have %s, maximum %d", header.BaseFee, MaximumL2BaseFee)
}
return nil
}
// CalcBaseFee calculates the basefee of the header.
func CalcBaseFee(config *params.ChainConfig, parent *types.Header, parentL1BaseFee *big.Int) *big.Int {
l2SequencerFee := big.NewInt(10000000) // 0.01 Gwei
provingFee := big.NewInt(140000000) // 0.14 Gwei
// L1_base_fee * 0.014
verificationFee := parentL1BaseFee
verificationFee = new(big.Int).Mul(verificationFee, big.NewInt(14))
verificationFee = new(big.Int).Div(verificationFee, big.NewInt(1000))
baseFee := big.NewInt(0)
baseFee.Add(baseFee, l2SequencerFee)
baseFee.Add(baseFee, provingFee)
baseFee.Add(baseFee, verificationFee)
if baseFee.Cmp(big.NewInt(MaximumL2BaseFee)) > 0 {
baseFee = big.NewInt(MaximumL2BaseFee)
}
return baseFee
}

View file

@ -16,6 +16,8 @@
package eip1559 package eip1559
/*
import ( import (
"math/big" "math/big"
"testing" "testing"
@ -129,3 +131,5 @@ func TestCalcBaseFee(t *testing.T) {
} }
} }
} }
*/

View file

@ -31,6 +31,7 @@ import (
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"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/fees"
"github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie"
) )
@ -179,7 +180,11 @@ func (b *BlockGen) Timestamp() uint64 {
// BaseFee returns the EIP-1559 base fee of the block being generated. // BaseFee returns the EIP-1559 base fee of the block being generated.
func (b *BlockGen) BaseFee() *big.Int { func (b *BlockGen) BaseFee() *big.Int {
return new(big.Int).Set(b.header.BaseFee) if b.header.BaseFee != nil {
return new(big.Int).Set(b.header.BaseFee)
} else {
return big.NewInt(0)
}
} }
// AddUncheckedReceipt forcefully adds a receipts to the block without a // AddUncheckedReceipt forcefully adds a receipts to the block without a
@ -217,12 +222,9 @@ func (b *BlockGen) AddUncle(h *types.Header) {
// The gas limit and price should be derived from the parent // The gas limit and price should be derived from the parent
h.GasLimit = parent.GasLimit h.GasLimit = parent.GasLimit
if b.config.IsLondon(h.Number) { if b.config.IsCurie(h.Number) {
h.BaseFee = eip1559.CalcBaseFee(b.config, parent) parentL1BaseFee := fees.GetL1BaseFee(b.statedb)
if !b.config.IsLondon(parent.Number) { h.BaseFee = eip1559.CalcBaseFee(b.config, parent, parentL1BaseFee)
parentGasLimit := parent.GasLimit * b.config.ElasticityMultiplier()
h.GasLimit = CalcGasLimit(parentGasLimit, parentGasLimit)
}
} }
b.uncles = append(b.uncles, h) b.uncles = append(b.uncles, h)
} }
@ -409,12 +411,9 @@ func makeHeader(chain consensus.ChainReader, parent *types.Block, state *state.S
Number: new(big.Int).Add(parent.Number(), common.Big1), Number: new(big.Int).Add(parent.Number(), common.Big1),
Time: time, Time: time,
} }
if chain.Config().IsLondon(header.Number) { if chain.Config().IsCurie(header.Number) {
header.BaseFee = eip1559.CalcBaseFee(chain.Config(), parent.Header()) parentL1BaseFee := fees.GetL1BaseFee(state)
if !chain.Config().IsLondon(parent.Number()) { header.BaseFee = eip1559.CalcBaseFee(chain.Config(), parent.Header(), parentL1BaseFee)
parentGasLimit := parent.GasLimit() * chain.Config().ElasticityMultiplier()
header.GasLimit = CalcGasLimit(parentGasLimit, parentGasLimit)
}
} }
if chain.Config().IsCancun(header.Number, header.Time) { if chain.Config().IsCancun(header.Number, header.Time) {
var ( var (

View file

@ -28,6 +28,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/consensus/misc/eip1559"
"github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
@ -450,14 +451,13 @@ func (g *Genesis) ToBlock() *types.Block {
if g.Difficulty == nil && g.Mixhash == (common.Hash{}) { if g.Difficulty == nil && g.Mixhash == (common.Hash{}) {
head.Difficulty = params.GenesisDifficulty head.Difficulty = params.GenesisDifficulty
} }
// TODO: fix basefee if g.Config != nil && g.Config.IsCurie(common.Big0) {
// if g.Config != nil && g.Config.IsLondon(common.Big0) { if g.BaseFee != nil {
// if g.BaseFee != nil { head.BaseFee = g.BaseFee
// head.BaseFee = g.BaseFee } else {
// } else { head.BaseFee = eip1559.CalcBaseFee(g.Config, nil, big.NewInt(0))
// head.BaseFee = new(big.Int).SetUint64(params.InitialBaseFee) }
// } }
// }
var withdrawals []*types.Withdrawal var withdrawals []*types.Withdrawal
// if conf := g.Config; conf != nil { // if conf := g.Config; conf != nil {
// num := big.NewInt(int64(g.Number)) // num := big.NewInt(int64(g.Number))

View file

@ -376,8 +376,9 @@ func GenerateBadBlock(parent *types.Block, engine consensus.Engine, txs types.Tr
Time: parent.Time() + 10, Time: parent.Time() + 10,
UncleHash: types.EmptyUncleHash, UncleHash: types.EmptyUncleHash,
} }
if config.IsLondon(header.Number) { if config.IsCurie(header.Number) {
header.BaseFee = eip1559.CalcBaseFee(config, parent.Header()) parentL1BaseFee := big.NewInt(1000000000) // 1 gwei
header.BaseFee = eip1559.CalcBaseFee(config, parent.Header(), parentL1BaseFee)
} }
if config.IsShanghai(header.Number, header.Time) { if config.IsShanghai(header.Number, header.Time) {
header.WithdrawalsHash = &types.EmptyWithdrawalsHash header.WithdrawalsHash = &types.EmptyWithdrawalsHash

View file

@ -335,6 +335,7 @@ func (st *StateTransition) preCheck() error {
} }
// Make sure that transaction gasFeeCap is greater than the baseFee (post london) // Make sure that transaction gasFeeCap is greater than the baseFee (post london)
// Note: Logically, this should be `IsCurie`, but we keep `IsLondon` to ensure backward compatibility.
if st.evm.ChainConfig().IsLondon(st.evm.Context.BlockNumber) { if st.evm.ChainConfig().IsLondon(st.evm.Context.BlockNumber) {
// Skip the checks if gas fields are zero and baseFee was explicitly disabled (eth_call) // Skip the checks if gas fields are zero and baseFee was explicitly disabled (eth_call)
if !st.evm.Config.NoBaseFee || msg.GasFeeCap.BitLen() > 0 || msg.GasTipCap.BitLen() > 0 { if !st.evm.Config.NoBaseFee || msg.GasFeeCap.BitLen() > 0 || msg.GasTipCap.BitLen() > 0 {
@ -352,7 +353,11 @@ func (st *StateTransition) preCheck() error {
} }
// This will panic if baseFee is nil, but basefee presence is verified // This will panic if baseFee is nil, but basefee presence is verified
// as part of header validation. // as part of header validation.
if msg.GasFeeCap.Cmp(st.evm.Context.BaseFee) < 0 { if st.evm.Context.BaseFee != nil && msg.GasFeeCap.Cmp(st.evm.Context.BaseFee) < 0 {
return fmt.Errorf("%w: address %v, maxFeePerGas: %s baseFee: %s", ErrFeeCapTooLow,
msg.From.Hex(), msg.GasFeeCap, st.evm.Context.BaseFee)
}
if st.evm.Context.BaseFee == nil && msg.GasFeeCap.Cmp(big.NewInt(0)) < 0 {
return fmt.Errorf("%w: address %v, maxFeePerGas: %s baseFee: %s", ErrFeeCapTooLow, return fmt.Errorf("%w: address %v, maxFeePerGas: %s baseFee: %s", ErrFeeCapTooLow,
msg.From.Hex(), msg.GasFeeCap, st.evm.Context.BaseFee) msg.From.Hex(), msg.GasFeeCap, st.evm.Context.BaseFee)
} }
@ -479,7 +484,9 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
st.refundGas(params.RefundQuotientEIP3529) st.refundGas(params.RefundQuotientEIP3529)
} }
effectiveTip := msg.GasPrice effectiveTip := msg.GasPrice
if rules.IsLondon {
// only burn the base fee if the fee vault is not enabled
if rules.IsCurie && !st.evm.ChainConfig().Scroll.FeeVaultEnabled() {
effectiveTip = cmath.BigMin(msg.GasTipCap, new(big.Int).Sub(msg.GasFeeCap, st.evm.Context.BaseFee)) effectiveTip = cmath.BigMin(msg.GasTipCap, new(big.Int).Sub(msg.GasFeeCap, st.evm.Context.BaseFee))
} }

View file

@ -41,6 +41,7 @@ import (
"github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rollup/fees"
"github.com/holiman/billy" "github.com/holiman/billy"
"github.com/holiman/uint256" "github.com/holiman/uint256"
) )
@ -399,7 +400,7 @@ func (p *BlobPool) Init(gasTip *big.Int, head *types.Header, reserve txpool.Addr
p.recheck(addr, nil) p.recheck(addr, nil)
} }
var ( var (
basefee = uint256.MustFromBig(eip1559.CalcBaseFee(p.chain.Config(), p.head)) basefee = uint256.MustFromBig(eip1559.CalcBaseFee(p.chain.Config(), p.head, fees.GetL1BaseFee(p.state)))
blobfee = uint256.MustFromBig(big.NewInt(params.BlobTxMinBlobGasprice)) blobfee = uint256.MustFromBig(big.NewInt(params.BlobTxMinBlobGasprice))
) )
if p.head.ExcessBlobGas != nil { if p.head.ExcessBlobGas != nil {
@ -782,7 +783,7 @@ func (p *BlobPool) Reset(oldHead, newHead *types.Header) {
} }
// Reset the price heap for the new set of basefee/blobfee pairs // Reset the price heap for the new set of basefee/blobfee pairs
var ( var (
basefee = uint256.MustFromBig(eip1559.CalcBaseFee(p.chain.Config(), newHead)) basefee = uint256.MustFromBig(eip1559.CalcBaseFee(p.chain.Config(), newHead, fees.GetL1BaseFee(p.state)))
blobfee = uint256.MustFromBig(big.NewInt(params.BlobTxMinBlobGasprice)) blobfee = uint256.MustFromBig(big.NewInt(params.BlobTxMinBlobGasprice))
) )
if newHead.ExcessBlobGas != nil { if newHead.ExcessBlobGas != nil {

View file

@ -109,12 +109,13 @@ func (bc *testBlockChain) CurrentBlock() *types.Header {
mid := new(big.Int).Add(lo, hi) mid := new(big.Int).Add(lo, hi)
mid.Div(mid, big.NewInt(2)) mid.Div(mid, big.NewInt(2))
parentL1BaseFee := big.NewInt(1000000000) // 1 gwei
if eip1559.CalcBaseFee(bc.config, &types.Header{ if eip1559.CalcBaseFee(bc.config, &types.Header{
Number: blockNumber, Number: blockNumber,
GasLimit: gasLimit, GasLimit: gasLimit,
GasUsed: 0, GasUsed: 0,
BaseFee: mid, BaseFee: mid,
}).Cmp(bc.basefee.ToBig()) > 0 { }, parentL1BaseFee).Cmp(bc.basefee.ToBig()) > 0 {
hi = mid hi = mid
} else { } else {
lo = mid lo = mid

View file

@ -37,6 +37,7 @@ import (
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rollup/fees"
) )
const ( const (
@ -1287,8 +1288,9 @@ func (pool *LegacyPool) runReorg(done chan struct{}, reset *txpoolResetRequest,
if reset != nil { if reset != nil {
pool.demoteUnexecutables() pool.demoteUnexecutables()
if reset.newHead != nil { if reset.newHead != nil {
if pool.chainconfig.IsLondon(new(big.Int).Add(reset.newHead.Number, big.NewInt(1))) { if pool.chainconfig.IsCurie(new(big.Int).Add(reset.newHead.Number, big.NewInt(1))) {
pendingBaseFee := eip1559.CalcBaseFee(pool.chainconfig, reset.newHead) l1BaseFee := fees.GetL1BaseFee(pool.currentState)
pendingBaseFee := eip1559.CalcBaseFee(pool.chainconfig, reset.newHead, l1BaseFee)
pool.priced.SetBaseFee(pendingBaseFee) pool.priced.SetBaseFee(pendingBaseFee)
} else { } else {
pool.priced.Reheap() pool.priced.Reheap()

View file

@ -58,10 +58,10 @@ func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types
return fmt.Errorf("%w: transaction size %v, limit %v", ErrOversizedData, tx.Size(), opts.MaxSize) return fmt.Errorf("%w: transaction size %v, limit %v", ErrOversizedData, tx.Size(), opts.MaxSize)
} }
// Ensure only transactions that have been enabled are accepted // Ensure only transactions that have been enabled are accepted
if !opts.Config.IsBerlin(head.Number) && tx.Type() != types.LegacyTxType { if !opts.Config.IsCurie(head.Number) && tx.Type() != types.LegacyTxType {
return fmt.Errorf("%w: type %d rejected, pool not yet in Berlin", core.ErrTxTypeNotSupported, tx.Type()) return fmt.Errorf("%w: type %d rejected, pool not yet in Berlin", core.ErrTxTypeNotSupported, tx.Type())
} }
if !opts.Config.IsLondon(head.Number) && tx.Type() == types.DynamicFeeTxType { if !opts.Config.IsCurie(head.Number) && tx.Type() == types.DynamicFeeTxType {
return fmt.Errorf("%w: type %d rejected, pool not yet in London", core.ErrTxTypeNotSupported, tx.Type()) return fmt.Errorf("%w: type %d rejected, pool not yet in London", core.ErrTxTypeNotSupported, tx.Type())
} }
if !opts.Config.IsCancun(head.Number, head.Time) && tx.Type() == types.BlobTxType { if !opts.Config.IsCancun(head.Number, head.Time) && tx.Type() == types.BlobTxType {

View file

@ -432,3 +432,7 @@ func (b *EthAPIBackend) StateAtBlock(ctx context.Context, block *types.Block, re
func (b *EthAPIBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) { func (b *EthAPIBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
return b.eth.stateAtTransaction(ctx, block, txIndex, reexec) return b.eth.stateAtTransaction(ctx, block, txIndex, reexec)
} }
func (b *EthAPIBackend) StateAt(root common.Hash) (*state.StateDB, error) {
return b.eth.BlockChain().StateAt(root)
}

View file

@ -30,6 +30,8 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rollup/fees"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
) )
@ -164,9 +166,17 @@ func (api *FilterAPI) NewPendingTransactions(ctx context.Context, fullTx *bool)
// To keep the original behaviour, send a single tx hash in one notification. // To keep the original behaviour, send a single tx hash in one notification.
// TODO(rjl493456442) Send a batch of tx hashes in one notification // TODO(rjl493456442) Send a batch of tx hashes in one notification
latest := api.sys.backend.CurrentHeader() latest := api.sys.backend.CurrentHeader()
state, err := api.sys.backend.StateAt(latest.Root)
if err != nil || state == nil {
log.Error("State not found", "number", latest.Number, "hash", latest.Hash().Hex(), "state", state, "err", err)
continue
}
l1BaseFee := fees.GetL1BaseFee(state)
for _, tx := range txs { for _, tx := range txs {
if fullTx != nil && *fullTx { if fullTx != nil && *fullTx {
rpcTx := ethapi.NewRPCPendingTransaction(tx, latest, chainConfig) rpcTx := ethapi.NewRPCPendingTransaction(tx, latest, chainConfig, l1BaseFee)
notifier.Notify(rpcSub.ID, rpcTx) notifier.Notify(rpcSub.ID, rpcTx)
} else { } else {
notifier.Notify(rpcSub.ID, tx.Hash()) notifier.Notify(rpcSub.ID, tx.Hash())
@ -438,9 +448,16 @@ func (api *FilterAPI) GetFilterChanges(id rpc.ID) (interface{}, error) {
return returnHashes(hashes), nil return returnHashes(hashes), nil
case PendingTransactionsSubscription: case PendingTransactionsSubscription:
if f.fullTx { if f.fullTx {
state, err := api.sys.backend.StateAt(latest.Root)
if err != nil || state == nil {
log.Error("State not found", "number", latest.Number, "hash", latest.Hash().Hex(), "state", state, "err", err)
return nil, errors.New("state not found")
}
l1BaseFee := fees.GetL1BaseFee(state)
txs := make([]*ethapi.RPCTransaction, 0, len(f.txs)) txs := make([]*ethapi.RPCTransaction, 0, len(f.txs))
for _, tx := range f.txs { for _, tx := range f.txs {
txs = append(txs, ethapi.NewRPCPendingTransaction(tx, latest, chainConfig)) txs = append(txs, ethapi.NewRPCPendingTransaction(tx, latest, chainConfig, l1BaseFee))
} }
f.txs = nil f.txs = nil
return txs, nil return txs, nil

View file

@ -32,6 +32,7 @@ import (
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/bloombits" "github.com/ethereum/go-ethereum/core/bloombits"
"github.com/ethereum/go-ethereum/core/rawdb" "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/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/event"
@ -65,6 +66,8 @@ type Backend interface {
GetLogs(ctx context.Context, blockHash common.Hash, number uint64) ([][]*types.Log, error) GetLogs(ctx context.Context, blockHash common.Hash, number uint64) ([][]*types.Log, error)
PendingBlockAndReceipts() (*types.Block, types.Receipts) PendingBlockAndReceipts() (*types.Block, types.Receipts)
StateAt(root common.Hash) (*state.StateDB, error)
CurrentHeader() *types.Header CurrentHeader() *types.Header
ChainConfig() *params.ChainConfig ChainConfig() *params.ChainConfig
SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription

View file

@ -29,6 +29,7 @@ import (
"github.com/ethereum/go-ethereum/consensus/misc/eip1559" "github.com/ethereum/go-ethereum/consensus/misc/eip1559"
"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/log"
"github.com/ethereum/go-ethereum/rollup/fees"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
"golang.org/x/exp/slices" "golang.org/x/exp/slices"
) )
@ -82,8 +83,14 @@ func (oracle *Oracle) processBlock(bf *blockFees, percentiles []float64) {
if bf.results.baseFee = bf.header.BaseFee; bf.results.baseFee == nil { if bf.results.baseFee = bf.header.BaseFee; bf.results.baseFee == nil {
bf.results.baseFee = new(big.Int) bf.results.baseFee = new(big.Int)
} }
if chainconfig.IsLondon(big.NewInt(int64(bf.blockNumber + 1))) { if chainconfig.IsCurie(big.NewInt(int64(bf.blockNumber + 1))) {
bf.results.nextBaseFee = eip1559.CalcBaseFee(chainconfig, bf.header) state, err := oracle.backend.StateAt(bf.header.Root)
if err != nil || state == nil {
log.Error("State not found", "number", bf.header.Number, "hash", bf.header.Hash().Hex(), "state", state, "err", err)
return
}
l1BaseFee := fees.GetL1BaseFee(state)
bf.results.nextBaseFee = eip1559.CalcBaseFee(chainconfig, bf.header, l1BaseFee)
} else { } else {
bf.results.nextBaseFee = new(big.Int) bf.results.nextBaseFee = new(big.Int)
} }

View file

@ -24,6 +24,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/lru" "github.com/ethereum/go-ethereum/common/lru"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"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/event" "github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
@ -57,6 +58,7 @@ type OracleBackend interface {
PendingBlockAndReceipts() (*types.Block, types.Receipts) PendingBlockAndReceipts() (*types.Block, types.Receipts)
ChainConfig() *params.ChainConfig ChainConfig() *params.ChainConfig
SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription
StateAt(root common.Hash) (*state.StateDB, error)
} }
// Oracle recommends gas prices based on the content of recent // Oracle recommends gas prices based on the content of recent

View file

@ -26,6 +26,7 @@ import (
"github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb" "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/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
@ -117,6 +118,10 @@ func (b *testBackend) teardown() {
b.chain.Stop() b.chain.Stop()
} }
func (b *testBackend) StateAt(root common.Hash) (*state.StateDB, error) {
return b.chain.StateAt(root)
}
// newTestBackend creates a test backend. OBS: don't forget to invoke tearDown // newTestBackend creates a test backend. OBS: don't forget to invoke tearDown
// after use, otherwise the blockchain instance will mem-leak via goroutines. // after use, otherwise the blockchain instance will mem-leak via goroutines.
func newTestBackend(t *testing.T, londonBlock *big.Int, pending bool) *testBackend { func newTestBackend(t *testing.T, londonBlock *big.Int, pending bool) *testBackend {

View file

@ -36,7 +36,9 @@ import (
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/eth/filters" "github.com/ethereum/go-ethereum/eth/filters"
"github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rollup/fees"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
) )
@ -769,11 +771,19 @@ func (b *Block) NextBaseFeePerGas(ctx context.Context) (*hexutil.Big, error) {
chaincfg := b.r.backend.ChainConfig() chaincfg := b.r.backend.ChainConfig()
if header.BaseFee == nil { if header.BaseFee == nil {
// Make sure next block doesn't enable EIP-1559 // Make sure next block doesn't enable EIP-1559
if !chaincfg.IsLondon(new(big.Int).Add(header.Number, common.Big1)) { if !chaincfg.IsCurie(new(big.Int).Add(header.Number, common.Big1)) {
return nil, nil return nil, nil
} }
} }
nextBaseFee := eip1559.CalcBaseFee(chaincfg, header)
state, err := b.r.backend.StateAt(header.Root)
if err != nil {
log.Error("Failed to get state", "err", err)
return nil, err
}
l1BaseFee := fees.GetL1BaseFee(state)
nextBaseFee := eip1559.CalcBaseFee(chaincfg, header, l1BaseFee)
return (*hexutil.Big)(nextBaseFee), nil return (*hexutil.Big)(nextBaseFee), nil
} }

View file

@ -169,11 +169,20 @@ func (s *TxPoolAPI) Content() map[string]map[string]map[string]*RPCTransaction {
} }
pending, queue := s.b.TxPoolContent() pending, queue := s.b.TxPoolContent()
curHeader := s.b.CurrentHeader() curHeader := s.b.CurrentHeader()
// get latest L1 base fee
state, err := s.b.StateAt(curHeader.Root)
if err != nil || state == nil {
log.Error("State not found", "number", curHeader.Number, "hash", curHeader.Hash().Hex(), "state", state, "err", err)
return nil
}
l1BaseFee := fees.GetL1BaseFee(state)
// Flatten the pending transactions // Flatten the pending transactions
for account, txs := range pending { for account, txs := range pending {
dump := make(map[string]*RPCTransaction) dump := make(map[string]*RPCTransaction)
for _, tx := range txs { for _, tx := range txs {
dump[fmt.Sprintf("%d", tx.Nonce())] = NewRPCPendingTransaction(tx, curHeader, s.b.ChainConfig()) dump[fmt.Sprintf("%d", tx.Nonce())] = NewRPCPendingTransaction(tx, curHeader, s.b.ChainConfig(), l1BaseFee)
} }
content["pending"][account.Hex()] = dump content["pending"][account.Hex()] = dump
} }
@ -181,7 +190,7 @@ func (s *TxPoolAPI) Content() map[string]map[string]map[string]*RPCTransaction {
for account, txs := range queue { for account, txs := range queue {
dump := make(map[string]*RPCTransaction) dump := make(map[string]*RPCTransaction)
for _, tx := range txs { for _, tx := range txs {
dump[fmt.Sprintf("%d", tx.Nonce())] = NewRPCPendingTransaction(tx, curHeader, s.b.ChainConfig()) dump[fmt.Sprintf("%d", tx.Nonce())] = NewRPCPendingTransaction(tx, curHeader, s.b.ChainConfig(), l1BaseFee)
} }
content["queued"][account.Hex()] = dump content["queued"][account.Hex()] = dump
} }
@ -194,17 +203,25 @@ func (s *TxPoolAPI) ContentFrom(addr common.Address) map[string]map[string]*RPCT
pending, queue := s.b.TxPoolContentFrom(addr) pending, queue := s.b.TxPoolContentFrom(addr)
curHeader := s.b.CurrentHeader() curHeader := s.b.CurrentHeader()
// get latest L1 base fee
state, err := s.b.StateAt(curHeader.Root)
if err != nil || state == nil {
log.Error("State not found", "number", curHeader.Number, "hash", curHeader.Hash().Hex(), "state", state, "err", err)
return nil
}
l1BaseFee := fees.GetL1BaseFee(state)
// Build the pending transactions // Build the pending transactions
dump := make(map[string]*RPCTransaction, len(pending)) dump := make(map[string]*RPCTransaction, len(pending))
for _, tx := range pending { for _, tx := range pending {
dump[fmt.Sprintf("%d", tx.Nonce())] = NewRPCPendingTransaction(tx, curHeader, s.b.ChainConfig()) dump[fmt.Sprintf("%d", tx.Nonce())] = NewRPCPendingTransaction(tx, curHeader, s.b.ChainConfig(), l1BaseFee)
} }
content["pending"] = dump content["pending"] = dump
// Build the queued transactions // Build the queued transactions
dump = make(map[string]*RPCTransaction, len(queue)) dump = make(map[string]*RPCTransaction, len(queue))
for _, tx := range queue { for _, tx := range queue {
dump[fmt.Sprintf("%d", tx.Nonce())] = NewRPCPendingTransaction(tx, curHeader, s.b.ChainConfig()) dump[fmt.Sprintf("%d", tx.Nonce())] = NewRPCPendingTransaction(tx, curHeader, s.b.ChainConfig(), l1BaseFee)
} }
content["queued"] = dump content["queued"] = dump
@ -1599,14 +1616,14 @@ func effectiveGasPrice(tx *types.Transaction, baseFee *big.Int) *big.Int {
} }
// NewRPCPendingTransaction returns a pending transaction that will serialize to the RPC representation // NewRPCPendingTransaction returns a pending transaction that will serialize to the RPC representation
func NewRPCPendingTransaction(tx *types.Transaction, current *types.Header, config *params.ChainConfig) *RPCTransaction { func NewRPCPendingTransaction(tx *types.Transaction, current *types.Header, config *params.ChainConfig, l1BaseFee *big.Int) *RPCTransaction {
var ( var (
baseFee *big.Int baseFee *big.Int
blockNumber = uint64(0) blockNumber = uint64(0)
blockTime = uint64(0) blockTime = uint64(0)
) )
if current != nil { if current != nil {
baseFee = eip1559.CalcBaseFee(config, current) baseFee = eip1559.CalcBaseFee(config, current, l1BaseFee)
blockNumber = current.Number.Uint64() blockNumber = current.Number.Uint64()
blockTime = current.Time blockTime = current.Time
} }
@ -1827,7 +1844,17 @@ func (s *TransactionAPI) GetTransactionByHash(ctx context.Context, hash common.H
} }
// No finalized transaction, try to retrieve it from the pool // No finalized transaction, try to retrieve it from the pool
if tx := s.b.GetPoolTransaction(hash); tx != nil { if tx := s.b.GetPoolTransaction(hash); tx != nil {
return NewRPCPendingTransaction(tx, s.b.CurrentHeader(), s.b.ChainConfig()), nil curHeader := s.b.CurrentHeader()
// get latest L1 base fee
state, err := s.b.StateAt(curHeader.Root)
if err != nil || state == nil {
log.Error("State not found", "number", curHeader.Number, "hash", curHeader.Hash().Hex(), "state", state, "err", err)
return nil, fmt.Errorf("cannot get L1 base fee, state not found")
}
l1BaseFee := fees.GetL1BaseFee(state)
return NewRPCPendingTransaction(tx, s.b.CurrentHeader(), s.b.ChainConfig(), l1BaseFee), nil
} }
// Transaction unknown, return as such // Transaction unknown, return as such
@ -2101,10 +2128,19 @@ func (s *TransactionAPI) PendingTransactions() ([]*RPCTransaction, error) {
} }
curHeader := s.b.CurrentHeader() curHeader := s.b.CurrentHeader()
transactions := make([]*RPCTransaction, 0, len(pending)) transactions := make([]*RPCTransaction, 0, len(pending))
// get latest L1 base fee
state, err := s.b.StateAt(curHeader.Root)
if err != nil || state == nil {
log.Error("State not found", "number", curHeader.Number, "hash", curHeader.Hash().Hex(), "state", state, "err", err)
return nil, fmt.Errorf("cannot get L1 base fee, state not found")
}
l1BaseFee := fees.GetL1BaseFee(state)
for _, tx := range pending { for _, tx := range pending {
from, _ := types.Sender(s.signer, tx) from, _ := types.Sender(s.signer, tx)
if _, exists := accounts[from]; exists { if _, exists := accounts[from]; exists {
transactions = append(transactions, NewRPCPendingTransaction(tx, curHeader, s.b.ChainConfig())) transactions = append(transactions, NewRPCPendingTransaction(tx, curHeader, s.b.ChainConfig(), l1BaseFee))
} }
} }
return transactions, nil return transactions, nil

View file

@ -604,6 +604,9 @@ func (b testBackend) BloomStatus() (uint64, uint64) { panic("implement me") }
func (b testBackend) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) { func (b testBackend) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) {
panic("implement me") panic("implement me")
} }
func (b testBackend) StateAt(root common.Hash) (*state.StateDB, error) {
return b.chain.StateAt(root)
}
func TestEstimateGas(t *testing.T) { func TestEstimateGas(t *testing.T) {
t.Parallel() t.Parallel()

View file

@ -65,6 +65,7 @@ type Backend interface {
BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Block, error) BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Block, error)
StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error)
StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error)
StateAt(root common.Hash) (*state.StateDB, error)
PendingBlockAndReceipts() (*types.Block, types.Receipts) PendingBlockAndReceipts() (*types.Block, types.Receipts)
GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error)
GetTd(ctx context.Context, hash common.Hash) *big.Int GetTd(ctx context.Context, hash common.Hash) *big.Int

View file

@ -138,7 +138,7 @@ func (args *TransactionArgs) setFeeDefaults(ctx context.Context, b Backend) erro
return errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified") return errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
} }
// If the tx has completely specified a fee mechanism, no default is needed. This allows users // If the tx has completely specified a fee mechanism, no default is needed. This allows users
// who are not yet synced past London to get defaults for other tx values. See // who are not yet synced past Curie to get defaults for other tx values. See
// https://github.com/ethereum/go-ethereum/pull/23274 for more information. // https://github.com/ethereum/go-ethereum/pull/23274 for more information.
eip1559ParamsSet := args.MaxFeePerGas != nil && args.MaxPriorityFeePerGas != nil eip1559ParamsSet := args.MaxFeePerGas != nil && args.MaxPriorityFeePerGas != nil
if (args.GasPrice != nil && !eip1559ParamsSet) || (args.GasPrice == nil && eip1559ParamsSet) { if (args.GasPrice != nil && !eip1559ParamsSet) || (args.GasPrice == nil && eip1559ParamsSet) {
@ -148,18 +148,18 @@ func (args *TransactionArgs) setFeeDefaults(ctx context.Context, b Backend) erro
} }
return nil return nil
} }
// Now attempt to fill in default value depending on whether London is active or not. // Now attempt to fill in default value depending on whether Curie is active or not.
head := b.CurrentHeader() head := b.CurrentHeader()
if b.ChainConfig().IsLondon(head.Number) { if b.ChainConfig().IsCurie(head.Number) {
// London is active, set maxPriorityFeePerGas and maxFeePerGas. // Curie is active, set maxPriorityFeePerGas and maxFeePerGas.
if err := args.setLondonFeeDefaults(ctx, head, b); err != nil { if err := args.setCurieFeeDefaults(ctx, head, b); err != nil {
return err return err
} }
} else { } else {
if args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil { if args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil {
return errors.New("maxFeePerGas and maxPriorityFeePerGas are not valid before London is active") return errors.New("maxFeePerGas and maxPriorityFeePerGas are not valid before Curie is active")
} }
// London not active, set gas price. // Curie not active, set gas price.
price, err := b.SuggestGasTipCap(ctx) price, err := b.SuggestGasTipCap(ctx)
if err != nil { if err != nil {
return err return err
@ -169,8 +169,8 @@ func (args *TransactionArgs) setFeeDefaults(ctx context.Context, b Backend) erro
return nil return nil
} }
// setLondonFeeDefaults fills in reasonable default fee values for unspecified fields. // setCurieFeeDefaults fills in reasonable default fee values for unspecified fields.
func (args *TransactionArgs) setLondonFeeDefaults(ctx context.Context, head *types.Header, b Backend) error { func (args *TransactionArgs) setCurieFeeDefaults(ctx context.Context, head *types.Header, b Backend) error {
// Set maxPriorityFeePerGas if it is missing. // Set maxPriorityFeePerGas if it is missing.
if args.MaxPriorityFeePerGas == nil { if args.MaxPriorityFeePerGas == nil {
tip, err := b.SuggestGasTipCap(ctx) tip, err := b.SuggestGasTipCap(ctx)
@ -181,13 +181,19 @@ func (args *TransactionArgs) setLondonFeeDefaults(ctx context.Context, head *typ
} }
// Set maxFeePerGas if it is missing. // Set maxFeePerGas if it is missing.
if args.MaxFeePerGas == nil { if args.MaxFeePerGas == nil {
// Set the max fee to be 2 times larger than the previous block's base fee. var val *big.Int
// The additional slack allows the tx to not become invalidated if the base if head.BaseFee != nil {
// fee is rising. // Set the max fee to be 2 times larger than the previous block's base fee.
val := new(big.Int).Add( // The additional slack allows the tx to not become invalidated if the base
args.MaxPriorityFeePerGas.ToInt(), // fee is rising.
new(big.Int).Mul(head.BaseFee, big.NewInt(2)), val = new(big.Int).Add(
) args.MaxPriorityFeePerGas.ToInt(),
new(big.Int).Mul(head.BaseFee, big.NewInt(2)),
)
} else {
val = new(big.Int).Set(
(*big.Int)(args.MaxPriorityFeePerGas))
}
args.MaxFeePerGas = (*hexutil.Big)(val) args.MaxFeePerGas = (*hexutil.Big)(val)
} }
// Both EIP-1559 fee parameters are now set; sanity check them. // Both EIP-1559 fee parameters are now set; sanity check them.

View file

@ -343,3 +343,7 @@ func (b *backendMock) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent)
} }
func (b *backendMock) Engine() consensus.Engine { return nil } func (b *backendMock) Engine() consensus.Engine { return nil }
func (b *backendMock) StateAt(root common.Hash) (*state.StateDB, error) {
return nil, nil
}

View file

@ -19,6 +19,7 @@ package les
import ( import (
"context" "context"
"errors" "errors"
"fmt"
"math/big" "math/big"
"time" "time"
@ -336,3 +337,7 @@ func (b *LesApiBackend) StateAtBlock(ctx context.Context, block *types.Block, re
func (b *LesApiBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) { func (b *LesApiBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
return b.eth.stateAtTransaction(ctx, block, txIndex, reexec) return b.eth.stateAtTransaction(ctx, block, txIndex, reexec)
} }
func (b *LesApiBackend) StateAt(root common.Hash) (*state.StateDB, error) {
return nil, fmt.Errorf("StateAt is not supported in LES protocol")
}

View file

@ -39,6 +39,7 @@ import (
"github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rollup/circuitcapacitychecker" "github.com/ethereum/go-ethereum/rollup/circuitcapacitychecker"
"github.com/ethereum/go-ethereum/rollup/fees"
"github.com/ethereum/go-ethereum/rollup/tracing" "github.com/ethereum/go-ethereum/rollup/tracing"
"github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie"
) )
@ -1346,13 +1347,16 @@ func (w *worker) prepareWork(genParams *generateParams) (*environment, error) {
if genParams.random != (common.Hash{}) { if genParams.random != (common.Hash{}) {
header.MixDigest = genParams.random header.MixDigest = genParams.random
} }
// Set baseFee and GasLimit if we are on an EIP-1559 chain // Set baseFee if we are on an EIP-1559 chain
if w.chainConfig.IsLondon(header.Number) { if w.chainConfig.IsCurie(header.Number) {
header.BaseFee = eip1559.CalcBaseFee(w.chainConfig, parent) state, err := w.chain.StateAt(parent.Root)
if !w.chainConfig.IsLondon(parent.Number) { if err != nil {
parentGasLimit := parent.GasLimit * w.chainConfig.ElasticityMultiplier() log.Error("Failed to create mining context", "err", err)
header.GasLimit = core.CalcGasLimit(parentGasLimit, w.config.GasCeil) return nil, err
} }
parentL1BaseFee := fees.GetL1BaseFee(state)
header.BaseFee = eip1559.CalcBaseFee(w.chainConfig, parent, parentL1BaseFee)
} }
// Apply EIP-4844, EIP-4788. // Apply EIP-4844, EIP-4788.
if w.chainConfig.IsCancun(header.Number, header.Time) { if w.chainConfig.IsCancun(header.Number, header.Time) {

View file

@ -187,3 +187,7 @@ func CalculateL1DataFee(tx *types.Transaction, state StateDB) (*big.Int, error)
l1DataFee := calculateEncodedL1DataFee(raw, overhead, l1BaseFee, scalar) l1DataFee := calculateEncodedL1DataFee(raw, overhead, l1BaseFee, scalar)
return l1DataFee, nil return l1DataFee, nil
} }
func GetL1BaseFee(state StateDB) *big.Int {
return state.GetState(rcfg.L1GasPriceOracleAddress, rcfg.L1BaseFeeSlot).Big()
}