diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index 801d4725a9b3..7a7ab8d85290 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -299,7 +299,23 @@ func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMs // state is modified during execution, make sure to copy it if necessary. func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallMsg, block *types.Block, statedb *state.StateDB) ([]byte, uint64, bool, error) { // Ensure message is initialized properly. - if call.GasPrice == nil { + // EIP1559 guards + if b.config.IsEIP1559Finalized(block.Number()) && (call.GasPremium == nil || call.FeeCap == nil || call.GasPrice != nil) { + return nil, 0, false, core.ErrTxNotEIP1559 + } + if !b.config.IsEIP1559(block.Number()) && (call.GasPremium != nil || call.FeeCap != nil || call.GasPrice == nil) { + return nil, 0, false, core.ErrTxIsEIP1559 + } + if call.GasPrice != nil && (call.GasPremium != nil || call.FeeCap != nil) { + return nil, 0, false, core.ErrTxSetsLegacyAndEIP1559Fields + } + if call.FeeCap != nil && call.GasPremium == nil { + return nil, 0, false, errors.New("if FeeCap is set, GasPremium must be set") + } + if call.GasPremium != nil && call.FeeCap == nil { + return nil, 0, false, errors.New("if GasPremium is set, FeeCap must be set") + } + if call.GasPrice == nil && call.GasPremium == nil { call.GasPrice = big.NewInt(1) } if call.Gas == 0 { @@ -319,8 +335,12 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM // about the transaction and calling mechanisms. vmenv := vm.NewEVM(evmContext, statedb, b.config, vm.Config{}) gaspool := new(core.GasPool).AddGas(math.MaxUint64) + var gp1559 *core.GasPool + if b.config.IsEIP1559(block.Number()) { + gp1559 = new(core.GasPool).AddGas(params.MaxGasEIP1559) + } - return core.NewStateTransition(vmenv, msg, gaspool).TransitionDb() + return core.NewStateTransition(vmenv, msg, gaspool, gp1559).TransitionDb() } // SendTransaction updates the pending block to include the given transaction. @@ -329,6 +349,20 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa b.mu.Lock() defer b.mu.Unlock() + // EIP1559 guards + if b.config.IsEIP1559Finalized(b.blockchain.CurrentBlock().Number()) && (tx.GasPremium() == nil || tx.FeeCap() == nil || tx.GasPrice() != nil) { + return core.ErrTxNotEIP1559 + } + if !b.config.IsEIP1559(b.blockchain.CurrentBlock().Number()) && (tx.GasPremium() != nil || tx.FeeCap() != nil || tx.GasPrice() == nil) { + return core.ErrTxIsEIP1559 + } + if tx.GasPrice() != nil && (tx.GasPremium() != nil || tx.FeeCap() != nil) { + return core.ErrTxSetsLegacyAndEIP1559Fields + } + if tx.GasPrice() == nil && (tx.GasPremium() == nil || tx.FeeCap() == nil) { + return core.ErrMissingGasFields + } + sender, err := types.Sender(types.NewEIP155Signer(b.config.ChainID), tx) if err != nil { panic(fmt.Errorf("invalid transaction: %v", err)) diff --git a/cmd/geth/retesteth.go b/cmd/geth/retesteth.go index b6aa3706b2b3..6de031446dd7 100644 --- a/cmd/geth/retesteth.go +++ b/cmd/geth/retesteth.go @@ -492,6 +492,10 @@ func (api *RetestethAPI) mineBlock() error { misc.ApplyDAOHardFork(statedb) } gasPool := new(core.GasPool).AddGas(header.GasLimit) + var gp1559 *core.GasPool + if api.chainConfig.IsEIP1559(header.Number) { + gp1559 = new(core.GasPool).AddGas(params.MaxGasEIP1559) + } txCount := 0 var txs []*types.Transaction var receipts []*types.Receipt @@ -513,6 +517,7 @@ func (api *RetestethAPI) mineBlock() error { api.blockchain, &api.author, gasPool, + gp1559, statedb, header, tx, &header.GasUsed, *api.blockchain.GetVMConfig(), ) @@ -657,7 +662,11 @@ func (api *RetestethAPI) AccountRange(ctx context.Context, context := core.NewEVMContext(msg, block.Header(), api.blockchain, nil) // Not yet the searched for transaction, execute on top of the current state vmenv := vm.NewEVM(context, statedb, api.blockchain.Config(), vm.Config{}) - if _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { + var gp1559 *core.GasPool + if vmenv.ChainConfig().IsEIP1559(block.Number()) { + gp1559 = new(core.GasPool).AddGas(params.MaxGasEIP1559) + } + if _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas()), gp1559); err != nil { return AccountRangeResult{}, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err) } // Ensure any modifications are committed to the state @@ -770,7 +779,11 @@ func (api *RetestethAPI) StorageRangeAt(ctx context.Context, context := core.NewEVMContext(msg, block.Header(), api.blockchain, nil) // Not yet the searched for transaction, execute on top of the current state vmenv := vm.NewEVM(context, statedb, api.blockchain.Config(), vm.Config{}) - if _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { + var gp1559 *core.GasPool + if vmenv.ChainConfig().IsEIP1559(block.Number()) { + gp1559 = new(core.GasPool).AddGas(params.MaxGasEIP1559) + } + if _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas()), gp1559); err != nil { return StorageRangeResult{}, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err) } // Ensure any modifications are committed to the state diff --git a/core/chain_makers.go b/core/chain_makers.go index 0b0fcdb4aa39..6a3363c41c66 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -39,10 +39,11 @@ type BlockGen struct { header *types.Header statedb *state.StateDB - gasPool *GasPool - txs []*types.Transaction - receipts []*types.Receipt - uncles []*types.Header + gasPool *GasPool + gasPool1559 *GasPool + txs []*types.Transaction + receipts []*types.Receipt + uncles []*types.Header config *params.ChainConfig engine consensus.Engine @@ -102,8 +103,11 @@ func (b *BlockGen) AddTxWithChain(bc *BlockChain, tx *types.Transaction) { if b.gasPool == nil { b.SetCoinbase(common.Address{}) } + if b.gasPool1559 == nil && b.config.IsEIP1559(b.header.Number) { + b.gasPool1559 = new(GasPool).AddGas(params.MaxGasEIP1559) + } b.statedb.Prepare(tx.Hash(), common.Hash{}, len(b.txs)) - receipt, err := ApplyTransaction(b.config, bc, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, vm.Config{}) + receipt, err := ApplyTransaction(b.config, bc, &b.header.Coinbase, b.gasPool, b.gasPool1559, b.statedb, b.header, tx, &b.header.GasUsed, vm.Config{}) if err != nil { panic(err) } diff --git a/core/evm.go b/core/evm.go index b654bbd4796f..662b6e960c60 100644 --- a/core/evm.go +++ b/core/evm.go @@ -55,6 +55,7 @@ func NewEVMContext(msg Message, header *types.Header, chain ChainContext, author Difficulty: new(big.Int).Set(header.Difficulty), GasLimit: header.GasLimit, GasPrice: new(big.Int).Set(msg.GasPrice()), + BaseFee: header.BaseFee, } } diff --git a/core/state_prefetcher.go b/core/state_prefetcher.go index cb85a05b578e..0efe6af4ee07 100644 --- a/core/state_prefetcher.go +++ b/core/state_prefetcher.go @@ -52,7 +52,11 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c var ( header = block.Header() gaspool = new(GasPool).AddGas(block.GasLimit()) + gp1559 *GasPool ) + if p.config.IsEIP1559(block.Number()) { + gp1559 = new(GasPool).AddGas(params.MaxGasEIP1559) + } // Iterate over and process the individual transactions for i, tx := range block.Transactions() { // If block precaching was interrupted, abort @@ -61,7 +65,7 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c } // Block precaching permitted to continue, execute the transaction statedb.Prepare(tx.Hash(), block.Hash(), i) - if err := precacheTransaction(p.config, p.bc, nil, gaspool, statedb, header, tx, cfg); err != nil { + if err := precacheTransaction(p.config, p.bc, nil, gaspool, gp1559, statedb, header, tx, cfg); err != nil { return // Ugh, something went horribly wrong, bail out } } @@ -70,7 +74,7 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c // precacheTransaction attempts to apply a transaction to the given state database // and uses the input parameters for its environment. The goal is not to execute // the transaction successfully, rather to warm up touched data slots. -func precacheTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gaspool *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, cfg vm.Config) error { +func precacheTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gaspool, gp1559 *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, cfg vm.Config) error { // Convert the transaction into an executable message and pre-cache its sender msg, err := tx.AsMessage(types.MakeSigner(config, header.Number)) if err != nil { @@ -80,6 +84,6 @@ func precacheTransaction(config *params.ChainConfig, bc ChainContext, author *co context := NewEVMContext(msg, header, bc, author) vm := vm.NewEVM(context, statedb, config, cfg) - _, _, _, err = ApplyMessage(vm, msg, gaspool) + _, _, _, err = ApplyMessage(vm, msg, gaspool, gp1559) return err } diff --git a/core/state_processor.go b/core/state_processor.go index cfe17d587b46..0f63a8d62674 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -60,7 +60,11 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg header = block.Header() allLogs []*types.Log gp = new(GasPool).AddGas(block.GasLimit()) + gp1559 *GasPool ) + if p.config.IsEIP1559(block.Number()) { + gp1559 = new(GasPool).AddGas(params.MaxGasEIP1559) + } // Mutate the block and state according to any hard-fork specs if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 { misc.ApplyDAOHardFork(statedb) @@ -68,7 +72,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg // Iterate over and process the individual transactions for i, tx := range block.Transactions() { statedb.Prepare(tx.Hash(), block.Hash(), i) - receipt, err := ApplyTransaction(p.config, p.bc, nil, gp, statedb, header, tx, usedGas, cfg) + receipt, err := ApplyTransaction(p.config, p.bc, nil, gp, gp1559, statedb, header, tx, usedGas, cfg) if err != nil { return nil, nil, 0, err } @@ -85,7 +89,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg // and uses the input parameters for its environment. It returns the receipt // for the transaction, gas used and an error if the transaction failed, // indicating the block was invalid. -func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, error) { +func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gp, gp1559 *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, error) { msg, err := tx.AsMessage(types.MakeSigner(config, header.Number)) if err != nil { return nil, err @@ -96,7 +100,7 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo // about the transaction and calling mechanisms. vmenv := vm.NewEVM(context, statedb, config, cfg) // Apply the transaction to the current state (included in the env) - _, gas, failed, err := ApplyMessage(vmenv, msg, gp) + _, gas, failed, err := ApplyMessage(vmenv, msg, gp, gp1559) if err != nil { return nil, err } diff --git a/core/state_transition.go b/core/state_transition.go index c63f819c16d7..9998d849a0c9 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -28,7 +28,8 @@ import ( ) var ( - errInsufficientBalanceForGas = errors.New("insufficient balance to pay for gas") + errInsufficientBalanceForGas = errors.New("insufficient balance to pay for gas") + errInsufficientCoinbaseBalance = errors.New("insufficient coinbase balance to apply a negative coinbase credit") ) /* @@ -49,15 +50,18 @@ The state transitioning model does all the necessary work to work out a valid ne 6) Derive new state root */ type StateTransition struct { - gp *GasPool - msg Message - gas uint64 - gasPrice *big.Int - initialGas uint64 - value *big.Int - data []byte - state vm.StateDB - evm *vm.EVM + gp *GasPool + gp1559 *GasPool + msg Message + gas uint64 + gasPrice *big.Int + initialGas uint64 + value *big.Int + data []byte + state vm.StateDB + evm *vm.EVM + isEIP1559 bool + eip1559GasPrice *big.Int } // Message represents a message sent to a contract. @@ -116,16 +120,27 @@ func IntrinsicGas(data []byte, contractCreation, isEIP155 bool, isEIP2028 bool) } // NewStateTransition initialises and returns a new state transition object. -func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition { - return &StateTransition{ - gp: gp, - evm: evm, - msg: msg, - gasPrice: msg.GasPrice(), - value: msg.Value(), - data: msg.Data(), - state: evm.StateDB, +func NewStateTransition(evm *vm.EVM, msg Message, gp, gp1559 *GasPool) *StateTransition { + isEIP1559 := evm.ChainConfig().IsEIP1559(evm.BlockNumber) && msg.GasPremium() != nil && msg.FeeCap() != nil && evm.BaseFee != nil && gp1559 != nil + st := &StateTransition{ + gp: gp, + gp1559: gp1559, + evm: evm, + msg: msg, + gasPrice: msg.GasPrice(), + value: msg.Value(), + data: msg.Data(), + state: evm.StateDB, + isEIP1559: isEIP1559, } + if isEIP1559 { + // EP1559 gasPrice = min(BASEFEE + tx.fee_premium, tx.fee_cap) + st.eip1559GasPrice = new(big.Int).Add(evm.BaseFee, msg.GasPremium()) + if st.eip1559GasPrice.Cmp(msg.FeeCap()) > 0 { + st.eip1559GasPrice.Set(msg.FeeCap()) + } + } + return st } // ApplyMessage computes the new state by applying the given message @@ -135,8 +150,8 @@ func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition // the gas used (which includes gas refunds) and an error if it failed. An error always // indicates a core error meaning that the message would always fail for that particular // state and would never be accepted within a block. -func ApplyMessage(evm *vm.EVM, msg Message, gp *GasPool) ([]byte, uint64, bool, error) { - return NewStateTransition(evm, msg, gp).TransitionDb() +func ApplyMessage(evm *vm.EVM, msg Message, gp, gp1559 *GasPool) ([]byte, uint64, bool, error) { + return NewStateTransition(evm, msg, gp, gp1559).TransitionDb() } // to returns the recipient of the message. @@ -157,6 +172,29 @@ func (st *StateTransition) useGas(amount uint64) error { } func (st *StateTransition) buyGas() error { + if st.isEIP1559 { + return st.buyGasEIP1559() + } + return st.buyGasLegacy() +} + +func (st *StateTransition) buyGasEIP1559() error { + // tx.origin pays gasPrice * tx.gas + mgval := new(big.Int).Mul(new(big.Int).SetUint64(st.msg.Gas()), st.eip1559GasPrice) + if st.state.GetBalance(st.msg.From()).Cmp(mgval) < 0 { + return errInsufficientBalanceForGas + } + if err := st.gp1559.SubGas(st.msg.Gas()); err != nil { + return err + } + st.gas += st.msg.Gas() + + st.initialGas = st.msg.Gas() + st.state.SubBalance(st.msg.From(), mgval) + return nil +} + +func (st *StateTransition) buyGasLegacy() error { mgval := new(big.Int).Mul(new(big.Int).SetUint64(st.msg.Gas()), st.gasPrice) if st.state.GetBalance(st.msg.From()).Cmp(mgval) < 0 { return errInsufficientBalanceForGas @@ -181,6 +219,26 @@ func (st *StateTransition) preCheck() error { return ErrNonceTooLow } } + // If we have reached the EIP1559 finalization block and we do not conform with EIP1559, throw an error + if st.evm.ChainConfig().IsEIP1559Finalized(st.evm.BlockNumber) && !st.isEIP1559 { + return ErrTxNotEIP1559 + } + // If we are before the EIP1559 initialization block, throw an error if we have EIP1559 fields or do not have a GasPrice + if !st.evm.ChainConfig().IsEIP1559(st.evm.BlockNumber) && (st.msg.GasPremium() != nil || st.msg.FeeCap() != nil || st.gp1559 != nil || st.evm.BaseFee != nil || st.msg.GasPrice() == nil) { + return ErrTxIsEIP1559 + } + // If transaction has both legacy and EIP1559 fields, throw an error + if (st.msg.GasPremium() != nil || st.msg.FeeCap() != nil) && st.msg.GasPrice() != nil { + return ErrTxSetsLegacyAndEIP1559Fields + } + // We need a BaseFee if we are past EIP1559 initialization + if st.evm.ChainConfig().IsEIP1559(st.evm.BlockNumber) && st.evm.BaseFee == nil { + return ErrNoBaseFee + } + // We need either a GasPrice or a FeeCap and GasPremium to be set + if st.msg.GasPrice() == nil && (st.msg.GasPremium() == nil || st.msg.FeeCap() == nil) { + return ErrMissingGasFields + } return st.buyGas() } @@ -230,12 +288,36 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo } } st.refundGas() + if st.isEIP1559 { + // block.coinbase gains (gasprice - BASEFEE) * gasused + coinBaseCredit := new(big.Int).Mul(new(big.Int).Sub(st.eip1559GasPrice, st.evm.BaseFee), new(big.Int).SetUint64(st.gasUsed())) + // If gasprice < BASEFEE (due to the fee_cap), this means that the block.coinbase loses funds from this operation; + // in this case, check that the post-balance is non-negative and throw an exception if it is negative. + if coinBaseCredit.Sign() < 0 { + coinbaseBal := st.state.GetBalance(st.evm.Coinbase) + postBalance := new(big.Int).Add(coinbaseBal, coinBaseCredit) + if postBalance.Sign() < 0 { + return nil, 0, vmerr != nil, errInsufficientCoinbaseBalance + } + } + st.state.AddBalance(st.evm.Coinbase, coinBaseCredit) + + return ret, st.gasUsed(), vmerr != nil, err + } st.state.AddBalance(st.evm.Coinbase, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), st.gasPrice)) return ret, st.gasUsed(), vmerr != nil, err } func (st *StateTransition) refundGas() { + if st.isEIP1559 { + st.refundGasEIP1559() + return + } + st.refundGasLegacy() +} + +func (st *StateTransition) refundGasLegacy() { // Apply refund counter, capped to half of the used gas. refund := st.gasUsed() / 2 if refund > st.state.GetRefund() { @@ -252,6 +334,24 @@ func (st *StateTransition) refundGas() { st.gp.AddGas(st.gas) } +func (st *StateTransition) refundGasEIP1559() { + // Apply refund counter, capped to half of the used gas. + refund := st.gasUsed() / 2 + if refund > st.state.GetRefund() { + refund = st.state.GetRefund() + } + st.gas += refund + + // tx.origin gets refunded gasprice * (tx.gas - gasused) + txGasSubUsed := new(big.Int).Sub(new(big.Int).SetUint64(st.msg.Gas()), new(big.Int).SetUint64(st.gasUsed())) + remaining := new(big.Int).Mul(st.eip1559GasPrice, txGasSubUsed) + st.state.AddBalance(st.msg.From(), remaining) + + // Also return remaining gas to the block gas counter so it is + // available for the next transaction. + st.gp1559.AddGas(st.gas) +} + // gasUsed returns the amount of gas used up by the state transition. func (st *StateTransition) gasUsed() uint64 { return st.initialGas - st.gas diff --git a/core/tx_pool.go b/core/tx_pool.go index f7032dbd1e8a..db3c55ea4b82 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -76,6 +76,25 @@ var ( // than some meaningful limit a user might use. This is not a consensus error // making the transaction invalid, rather a DOS protection. ErrOversizedData = errors.New("oversized data") + + // ErrTxNotEIP1559 is returned if we have reached the EIP1559 finalized block height + // and the input transaction does not conform to with EIP1559 + ErrTxNotEIP1559 = fmt.Errorf("after block %d EIP1559 is finalized and transactions must contain a GasPremium and FeeCap and not contain a GasPrice", params.EIP1559ForkFinalizedBlockNumber) + + // ErrTxIsEIP1559 is returned if we have not reached the EIP1559 initialization block height + // and the input transaction is not of the legacy type + ErrTxIsEIP1559 = fmt.Errorf("before block %d EIP1559 is not activated and transactions must contain a GasPrice and not contain a GasPremium or FeeCap", params.EIP1559ForkBlockNumber) + + // ErrTxSetsLegacyAndEIP1559Fields is returned if a transaction attempts to set + // both legacy (GasPrice) and EIP1559 (GasPremium and FeeCap) fields + ErrTxSetsLegacyAndEIP1559Fields = errors.New("transaction sets both legacy and EIP1559 fields") + + // ErrNoBaseFee is returned if we are past the EIP1559 initialization block but + // the current header does not provide a BaseFee + ErrNoBaseFee = errors.New("current header does not provide the BaseFee needed to process EIP1559 transactions") + + // ErrMissingGasFields is returned if neither GasPrice nor GasPremium and FeeCap are set + ErrMissingGasFields = errors.New("either GasPrice or GasPremium and FeeCap need to be set") ) var ( @@ -510,6 +529,33 @@ func (pool *TxPool) local() map[common.Address]types.Transactions { // validateTx checks whether a transaction is valid according to the consensus // rules and adheres to some heuristic limits of the local node (price and size). func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { + // EIP1559 guards + if pool.chainconfig.IsEIP1559(pool.chain.CurrentBlock().Number()) && pool.chain.CurrentBlock().BaseFee() == nil { + return ErrNoBaseFee + } + if pool.chainconfig.IsEIP1559Finalized(pool.chain.CurrentBlock().Number()) && (tx.GasPremium() == nil || tx.FeeCap() == nil || tx.GasPrice() != nil) { + return ErrTxNotEIP1559 + } + if !pool.chainconfig.IsEIP1559(pool.chain.CurrentBlock().Number()) && (tx.GasPremium() != nil || tx.FeeCap() != nil || tx.GasPrice() == nil) { + return ErrTxIsEIP1559 + } + if tx.GasPrice() != nil && (tx.GasPremium() != nil || tx.FeeCap() != nil) { + return ErrTxSetsLegacyAndEIP1559Fields + } + if tx.GasPrice() == nil && (tx.GasPremium() == nil || tx.FeeCap() == nil) { + return ErrMissingGasFields + } + // Set the gasPrice to the tx.GasPrice() if it is non nil (legacy transaction) + var gasPrice *big.Int + if tx.GasPrice() != nil { + gasPrice = tx.GasPrice() + } else { // Derive the gasPrice from the tx.GasPremium() and tx.FeeCap() (EIP1559 transaction) + gasPrice = new(big.Int).Add(pool.chain.CurrentBlock().BaseFee(), tx.GasPremium()) + if gasPrice.Cmp(tx.FeeCap()) > 0 { + gasPrice.Set(tx.FeeCap()) + } + } + // Heuristic limit, reject transactions over 32KB to prevent DOS attacks if tx.Size() > 32*1024 { return ErrOversizedData @@ -530,7 +576,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { } // Drop non-local transactions under our own minimal accepted gas price local = local || pool.locals.contains(from) // account may be local even if the transaction arrived from the network - if !local && pool.gasPrice.Cmp(tx.GasPrice()) > 0 { + if !local && pool.gasPrice.Cmp(gasPrice) > 0 { return ErrUnderpriced } // Ensure the transaction adheres to nonce ordering diff --git a/core/vm/evm.go b/core/vm/evm.go index 751c1fdc1f41..5926e452a99c 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -91,6 +91,7 @@ type Context struct { BlockNumber *big.Int // Provides information for NUMBER Time *big.Int // Provides information for TIME Difficulty *big.Int // Provides information for DIFFICULTY + BaseFee *big.Int // Provides information for BASEFEE } // EVM is the Ethereum Virtual Machine base object and provides diff --git a/eth/api_tracer.go b/eth/api_tracer.go index ce211cbd99ef..70e00bdad35c 100644 --- a/eth/api_tracer.go +++ b/eth/api_tracer.go @@ -28,6 +28,8 @@ import ( "sync" "time" + "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core" @@ -491,6 +493,7 @@ func (api *PrivateDebugAPI) traceBlock(ctx context.Context, block *types.Block, } }() } + var gp1559 *core.GasPool // Feed the transactions into the tracers and return var failed error for i, tx := range txs { @@ -501,8 +504,11 @@ func (api *PrivateDebugAPI) traceBlock(ctx context.Context, block *types.Block, msg, _ := tx.AsMessage(signer) vmctx := core.NewEVMContext(msg, block.Header(), api.eth.blockchain, nil) + if api.eth.blockchain.Config().IsEIP1559(block.Number()) { + gp1559 = new(core.GasPool).AddGas(params.MaxGasEIP1559) + } vmenv := vm.NewEVM(vmctx, statedb, api.eth.blockchain.Config(), vm.Config{}) - if _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil { + if _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()), gp1559); err != nil { failed = err break } @@ -563,6 +569,7 @@ func (api *PrivateDebugAPI) standardTraceBlockToFile(ctx context.Context, block var ( signer = types.MakeSigner(api.eth.blockchain.Config(), block.Number()) dumps []string + gp1559 *core.GasPool ) for i, tx := range block.Transactions() { // Prepare the trasaction for un-traced execution @@ -596,7 +603,10 @@ func (api *PrivateDebugAPI) standardTraceBlockToFile(ctx context.Context, block } // Execute the transaction and flush any traces to disk vmenv := vm.NewEVM(vmctx, statedb, api.eth.blockchain.Config(), vmConf) - _, _, _, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())) + if api.eth.blockchain.Config().IsEIP1559(block.Number()) { + gp1559 = new(core.GasPool).AddGas(params.MaxGasEIP1559) + } + _, _, _, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()), gp1559) if writer != nil { writer.Flush() } @@ -727,7 +737,11 @@ func (api *PrivateDebugAPI) traceTx(ctx context.Context, message core.Message, v var ( tracer vm.Tracer err error + gp1559 *core.GasPool ) + if api.eth.blockchain.Config().IsEIP1559(vmctx.BlockNumber) { + gp1559 = new(core.GasPool).AddGas(params.MaxGasEIP1559) + } switch { case config != nil && config.Tracer != nil: // Define a meaningful timeout of a single transaction trace @@ -758,7 +772,7 @@ func (api *PrivateDebugAPI) traceTx(ctx context.Context, message core.Message, v // Run the transaction with tracing enabled. vmenv := vm.NewEVM(vmctx, statedb, api.eth.blockchain.Config(), vm.Config{Debug: true, Tracer: tracer}) - ret, gas, failed, err := core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas())) + ret, gas, failed, err := core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas()), gp1559) if err != nil { return nil, fmt.Errorf("tracing failed: %v", err) } @@ -810,9 +824,13 @@ func (api *PrivateDebugAPI) computeTxEnv(blockHash common.Hash, txIndex int, ree if idx == txIndex { return msg, context, statedb, nil } + var gp1559 *core.GasPool + if api.eth.blockchain.Config().IsEIP1559(block.Number()) { + gp1559 = new(core.GasPool).AddGas(params.MaxGasEIP1559) + } // Not yet the searched for transaction, execute on top of the current state vmenv := vm.NewEVM(context, statedb, api.eth.blockchain.Config(), vm.Config{}) - if _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { + if _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas()), gp1559); err != nil { return nil, vm.Context{}, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err) } // Ensure any modifications are committed to the state diff --git a/eth/handler_test.go b/eth/handler_test.go index 35a2635afa0c..8a107c461009 100644 --- a/eth/handler_test.go +++ b/eth/handler_test.go @@ -388,8 +388,8 @@ func testGetReceipt(t *testing.T, protocol int) { case 1: // In block 2, the test bank sends some more ether to account #1. // acc1Addr passes it on to account #2. - tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil, nil, nil), signer, testBankKey) - tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil, nil, nil), signer, acc1Key) + tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil, nil, nil), signer, testBankKey) + tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil, nil, nil), signer, acc1Key) block.AddTx(tx1) block.AddTx(tx2) case 2: diff --git a/eth/tracers/tracers_test.go b/eth/tracers/tracers_test.go index aba809ff5a8c..c3f7b8c667c1 100644 --- a/eth/tracers/tracers_test.go +++ b/eth/tracers/tracers_test.go @@ -110,6 +110,7 @@ type callContext struct { Time math.HexOrDecimal64 `json:"timestamp"` GasLimit math.HexOrDecimal64 `json:"gasLimit"` Miner common.Address `json:"miner"` + BaseFee *math.HexOrDecimal256 `json:"baseFee"` } // callTracerTest defines a single test to check the call tracer against. @@ -181,7 +182,7 @@ func TestPrestateTracerCreate2(t *testing.T) { if err != nil { t.Fatalf("failed to prepare transaction for tracing: %v", err) } - st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas())) + st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas()), nil) if _, _, _, err = st.TransitionDb(); err != nil { t.Fatalf("failed to execute transaction: %v", err) } @@ -241,6 +242,7 @@ func TestCallTracer(t *testing.T) { Difficulty: (*big.Int)(test.Context.Difficulty), GasLimit: uint64(test.Context.GasLimit), GasPrice: tx.GasPrice(), + BaseFee: (*big.Int)(test.Context.BaseFee), } statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc) @@ -255,7 +257,11 @@ func TestCallTracer(t *testing.T) { if err != nil { t.Fatalf("failed to prepare transaction for tracing: %v", err) } - st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas())) + var gp1559 *core.GasPool + if test.Genesis.Config.IsEIP1559(context.BlockNumber) { + gp1559 = new(core.GasPool).AddGas(params.MaxGasEIP1559) + } + st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas()), gp1559) if _, _, _, err = st.TransitionDb(); err != nil { t.Fatalf("failed to execute transaction: %v", err) } diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index e4294c1e74e2..3b89fea9e63b 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -763,14 +763,14 @@ func DoCall(ctx context.Context, b Backend, args CallArgs, blockNrOrHash rpc.Blo defer func(start time.Time) { log.Debug("Executing EVM call finished", "runtime", time.Since(start)) }(time.Now()) // EIP1559 guards - if b.ChainConfig().IsEIP1559Finalized(b.CurrentBlock().Number()) && args.GasPremium == nil || args.FeeCap == nil || args.GasPrice != nil { - return nil, 0, false, fmt.Errorf("after block %d EIP1559 is finalized and transactions must contain a GasPremium and FeeCap and not contain a GasPrice", b.ChainConfig().EIP1559FinalizedBlock.Uint64()) + if b.ChainConfig().IsEIP1559Finalized(b.CurrentBlock().Number()) && (args.GasPremium == nil || args.FeeCap == nil || args.GasPrice != nil) { + return nil, 0, false, core.ErrTxNotEIP1559 } - if !b.ChainConfig().IsEIP1559(b.CurrentBlock().Number()) && args.GasPremium != nil || args.FeeCap != nil || args.GasPrice == nil { - return nil, 0, false, fmt.Errorf("before block %d EIP1559 is not activated and transactions must contain a GasPrice and not contain a GasPremium or FeeCap", b.ChainConfig().EIP1559Block.Uint64()) + if !b.ChainConfig().IsEIP1559(b.CurrentBlock().Number()) && (args.GasPremium != nil || args.FeeCap != nil || args.GasPrice == nil) { + return nil, 0, false, core.ErrTxIsEIP1559 } if args.GasPrice != nil && (args.GasPremium != nil || args.FeeCap != nil) { - return nil, 0, false, errors.New("if GasPrice is set, GasPremium and FeeCap must not be set") + return nil, 0, false, core.ErrTxSetsLegacyAndEIP1559Fields } if args.FeeCap != nil && args.GasPremium == nil { return nil, 0, false, errors.New("if FeeCap is set, GasPremium must be set") @@ -880,7 +880,11 @@ func DoCall(ctx context.Context, b Backend, args CallArgs, blockNrOrHash rpc.Blo // Setup the gas pool (also for unmetered requests) // and apply the message. gp := new(core.GasPool).AddGas(math.MaxUint64) - res, gas, failed, err := core.ApplyMessage(evm, msg, gp) + var gp1559 *core.GasPool + if evm.ChainConfig().IsEIP1559(header.Number) { + gp1559 = new(core.GasPool).AddGas(params.MaxGasEIP1559) + } + res, gas, failed, err := core.ApplyMessage(evm, msg, gp, gp1559) if err := vmError(); err != nil { return nil, 0, false, err } @@ -1391,14 +1395,14 @@ type SendTxArgs struct { // setDefaults is a helper function that fills in default values for unspecified tx fields. func (args *SendTxArgs) setDefaults(ctx context.Context, b Backend) error { // EIP1559 guards - if b.ChainConfig().IsEIP1559Finalized(b.CurrentBlock().Number()) && args.GasPremium == nil || args.FeeCap == nil || args.GasPrice != nil { - return fmt.Errorf("after block %d EIP1559 is finalized and transactions must contain a GasPremium and FeeCap and not contain a GasPrice", b.ChainConfig().EIP1559FinalizedBlock.Uint64()) + if b.ChainConfig().IsEIP1559Finalized(b.CurrentBlock().Number()) && (args.GasPremium == nil || args.FeeCap == nil || args.GasPrice != nil) { + return core.ErrTxNotEIP1559 } - if !b.ChainConfig().IsEIP1559(b.CurrentBlock().Number()) && args.GasPremium != nil || args.FeeCap != nil || args.GasPrice == nil { - return fmt.Errorf("before block %d EIP1559 is not activated and transactions must contain a GasPrice and not contain a GasPremium or FeeCap", b.ChainConfig().EIP1559Block.Uint64()) + if !b.ChainConfig().IsEIP1559(b.CurrentBlock().Number()) && (args.GasPremium != nil || args.FeeCap != nil || args.GasPrice == nil) { + return core.ErrTxIsEIP1559 } if args.GasPrice != nil && (args.GasPremium != nil || args.FeeCap != nil) { - return errors.New("if GasPrice is set, GasPremium and FeeCap must not be set") + return core.ErrTxSetsLegacyAndEIP1559Fields } if args.FeeCap != nil && args.GasPremium == nil { return errors.New("if FeeCap is set, GasPremium must be set") @@ -1555,20 +1559,17 @@ func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, encod return common.Hash{}, err } // EIP1559 guards - if s.b.ChainConfig().IsEIP1559Finalized(s.b.CurrentBlock().Number()) && tx.GasPremium() == nil || tx.FeeCap() == nil || tx.GasPrice() != nil { - return common.Hash{}, fmt.Errorf("after block %d EIP1559 is finalized and transactions must contain a GasPremium and FeeCap and not contain a GasPrice", s.b.ChainConfig().EIP1559FinalizedBlock.Uint64()) + if s.b.ChainConfig().IsEIP1559Finalized(s.b.CurrentBlock().Number()) && (tx.GasPremium() == nil || tx.FeeCap() == nil || tx.GasPrice() != nil) { + return common.Hash{}, core.ErrTxNotEIP1559 } - if !s.b.ChainConfig().IsEIP1559(s.b.CurrentBlock().Number()) && tx.GasPremium() != nil || tx.FeeCap() != nil || tx.GasPrice() == nil { - return common.Hash{}, fmt.Errorf("before block %d EIP1559 is not activated and transactions must contain a GasPrice and not contain a GasPremium or FeeCap", s.b.ChainConfig().EIP1559Block.Uint64()) + if !s.b.ChainConfig().IsEIP1559(s.b.CurrentBlock().Number()) && (tx.GasPremium() != nil || tx.FeeCap() != nil || tx.GasPrice() == nil) { + return common.Hash{}, core.ErrTxIsEIP1559 } if tx.GasPrice() != nil && (tx.GasPremium() != nil || tx.FeeCap() != nil) { - return common.Hash{}, errors.New("if GasPrice is set, GasPremium and FeeCap must not be set") - } - if tx.FeeCap() != nil && tx.GasPremium() == nil { - return common.Hash{}, errors.New("if FeeCap is set, GasPremium must be set") + return common.Hash{}, core.ErrTxSetsLegacyAndEIP1559Fields } - if tx.GasPremium() != nil && tx.FeeCap() == nil { - return common.Hash{}, errors.New("if GasPremium is set, FeeCap must be set") + if tx.GasPrice() == nil && (tx.GasPremium() == nil || tx.FeeCap() == nil) { + return common.Hash{}, core.ErrMissingGasFields } return SubmitTransaction(ctx, s.b, tx) } diff --git a/les/odr_test.go b/les/odr_test.go index fe67a8d43b62..74795a5a64d1 100644 --- a/les/odr_test.go +++ b/les/odr_test.go @@ -135,7 +135,11 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai //vmenv := core.NewEnv(statedb, config, bc, msg, header, vm.Config{}) gp := new(core.GasPool).AddGas(math.MaxUint64) - ret, _, _, _ := core.ApplyMessage(vmenv, msg, gp) + var gp1559 *core.GasPool + if config.IsEIP1559(header.Number) { + gp1559 = new(core.GasPool).AddGas(params.MaxGasEIP1559) + } + ret, _, _, _ := core.ApplyMessage(vmenv, msg, gp, gp1559) res = append(res, ret...) } } else { @@ -146,7 +150,11 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai context := core.NewEVMContext(msg, header, lc, nil) vmenv := vm.NewEVM(context, state, config, vm.Config{}) gp := new(core.GasPool).AddGas(math.MaxUint64) - ret, _, _, _ := core.ApplyMessage(vmenv, msg, gp) + var gp1559 *core.GasPool + if config.IsEIP1559(header.Number) { + gp1559 = new(core.GasPool).AddGas(params.MaxGasEIP1559) + } + ret, _, _, _ := core.ApplyMessage(vmenv, msg, gp, gp1559) if state.Error() == nil { res = append(res, ret...) } diff --git a/light/odr_test.go b/light/odr_test.go index ff756181639b..15d5843b4699 100644 --- a/light/odr_test.go +++ b/light/odr_test.go @@ -198,7 +198,11 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain context := core.NewEVMContext(msg, header, chain, nil) vmenv := vm.NewEVM(context, st, config, vm.Config{}) gp := new(core.GasPool).AddGas(math.MaxUint64) - ret, _, _, _ := core.ApplyMessage(vmenv, msg, gp) + var gp1559 *core.GasPool + if config.IsEIP1559(header.Number) { + gp1559 = new(core.GasPool).AddGas(params.MaxGasEIP1559) + } + ret, _, _, _ := core.ApplyMessage(vmenv, msg, gp, gp1559) res = append(res, ret...) if st.Error() != nil { return res, st.Error() diff --git a/miner/worker.go b/miner/worker.go index 183499ec308d..17d8974efb12 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -86,6 +86,7 @@ type environment struct { uncles mapset.Set // uncle set tcount int // tx count in cycle gasPool *core.GasPool // available gas used to pack transactions + gp1559 *core.GasPool // available gas used to pack EIP1559 transactions header *types.Header txs []*types.Transaction @@ -454,7 +455,21 @@ func (w *worker) mainLoop() { // be automatically eliminated. if !w.isRunning() && w.current != nil { // If block is already full, abort - if gp := w.current.gasPool; gp != nil && gp.Gas() < params.TxGas { + legacyGasPool := w.current.gasPool + eip1559GasPool := w.current.gp1559 + // If EIP1559 is finalized we only accept 1559 transactions so if that pool is exhausted the block is full + if w.chainConfig.IsEIP1559Finalized(w.chain.CurrentBlock().Number()) && eip1559GasPool != nil && eip1559GasPool.Gas() < params.TxGas { + continue + } + // If EIP1559 has not been initialized we only accept legacy transaction so if that pool is exhausted the block is full + if !w.chainConfig.IsEIP1559(w.chain.CurrentBlock().Number()) && legacyGasPool != nil && legacyGasPool.Gas() < params.TxGas { + continue + } + // When we are between EIP1559 initialization and finalization we can received transactions of both types + // and one pool could be exhausted while the other is not + // If both pools are exhausted we know the block is full but if only one is we could still accept transactions + // of the other type so we need to proceed into commitTransactions() + if legacyGasPool != nil && legacyGasPool.Gas() < params.TxGas && eip1559GasPool != nil && eip1559GasPool.Gas() < params.TxGas { continue } w.mu.RLock() @@ -483,7 +498,7 @@ func (w *worker) mainLoop() { } atomic.AddInt32(&w.newTxs, int32(len(ev.Txs))) - // System stopped + // System stopped case <-w.exitCh: return case <-w.txsSub.Err(): @@ -704,7 +719,7 @@ func (w *worker) updateSnapshot() { func (w *worker) commitTransaction(tx *types.Transaction, coinbase common.Address) ([]*types.Log, error) { snap := w.current.state.Snapshot() - receipt, err := core.ApplyTransaction(w.chainConfig, w.chain, &coinbase, w.current.gasPool, w.current.state, w.current.header, tx, &w.current.header.GasUsed, *w.chain.GetVMConfig()) + receipt, err := core.ApplyTransaction(w.chainConfig, w.chain, &coinbase, w.current.gasPool, w.current.gp1559, w.current.state, w.current.header, tx, &w.current.header.GasUsed, *w.chain.GetVMConfig()) if err != nil { w.current.state.RevertToSnapshot(snap) return nil, err @@ -721,13 +736,60 @@ func (w *worker) commitTransactions(txs *types.TransactionsByPriceAndNonce, coin return true } - if w.current.gasPool == nil { + if !w.chainConfig.IsEIP1559Finalized(w.current.header.Number) && w.current.gasPool == nil { w.current.gasPool = new(core.GasPool).AddGas(w.current.header.GasLimit) } + if w.chainConfig.IsEIP1559(w.current.header.Number) && w.current.gp1559 == nil { + w.current.gp1559 = new(core.GasPool).AddGas(params.MaxGasEIP1559) + } + oneTxType := false + if w.chainConfig.IsEIP1559Finalized(w.current.header.Number) || !w.chainConfig.IsEIP1559(w.current.header.Number) { + oneTxType = true + } var coalescedLogs []*types.Log for { + // Retrieve the next transaction and abort if all done + tx := txs.Peek() + if tx == nil { + break + } + // Set which gasPool to use based on the type of transaction + eip1559 := false + var gp *core.GasPool + if w.chainConfig.IsEIP1559(w.current.header.Number) && tx.GasPrice() == nil && tx.GasPremium() != nil && tx.FeeCap() != nil { + gp = w.current.gp1559 + eip1559 = true + } else if !w.chainConfig.IsEIP1559Finalized(w.current.header.Number) && tx.GasPremium() == nil && tx.FeeCap() == nil && tx.GasPrice() != nil { + gp = w.current.gasPool + } else { + log.Error("Transaction does not conform with expected format (legacy or EIP1559)") + continue + } + + // If we processing both types of transactions then we can break if both pools are exhausted + if w.current.gasPool != nil && w.current.gasPool.Gas() < params.TxGas && w.current.gp1559 != nil && w.current.gp1559.Gas() < params.TxGas { + log.Trace("Not enough gas for further transactions", "have legacy pool", w.current.gasPool, "and eip1559 pool", w.current.gp1559, "want", params.TxGas) + break + } + + // If we don't have enough gas for any further transactions of this type + if gp.Gas() < params.TxGas { + if eip1559 { + log.Trace("Not enough gas for further EIP1559 transactions", "have", gp, "want", params.TxGas) + } else { + log.Trace("Not enough gas for further legacy transactions", "have", gp, "want", params.TxGas) + } + // and this is the only type we are processing, then we're done + if oneTxType { + break + } + // Otherwise if only the current pool is exhausted we need to continue + // in case some of the subsequent transactions are for the non-exhausted pool + continue + } + // In the following three cases, we will interrupt the execution of the transaction. // (1) new head block event arrival, the interrupt signal is 1 // (2) worker start or restart, the interrupt signal is 1 @@ -737,7 +799,12 @@ func (w *worker) commitTransactions(txs *types.TransactionsByPriceAndNonce, coin if interrupt != nil && atomic.LoadInt32(interrupt) != commitInterruptNone { // Notify resubmit loop to increase resubmitting interval due to too frequent commits. if atomic.LoadInt32(interrupt) == commitInterruptResubmit { - ratio := float64(w.current.header.GasLimit-w.current.gasPool.Gas()) / float64(w.current.header.GasLimit) + var ratio float64 + if eip1559 { + ratio = float64(params.MaxGasEIP1559-gp.Gas()) / float64(params.MaxGasEIP1559) + } else { + ratio = float64(w.current.header.GasLimit-gp.Gas()) / float64(w.current.header.GasLimit) + } if ratio < 0.1 { ratio = 0.1 } @@ -748,16 +815,7 @@ func (w *worker) commitTransactions(txs *types.TransactionsByPriceAndNonce, coin } return atomic.LoadInt32(interrupt) == commitInterruptNewHead } - // If we don't have enough gas for any further transactions then we're done - if w.current.gasPool.Gas() < params.TxGas { - log.Trace("Not enough gas for further transactions", "have", w.current.gasPool, "want", params.TxGas) - break - } - // Retrieve the next transaction and abort if all done - tx := txs.Peek() - if tx == nil { - break - } + // Error may be ignored here. The error has already been checked // during transaction acceptance is the transaction pool. // diff --git a/tests/state_test_util.go b/tests/state_test_util.go index 19d3689e2d18..129a04fd29d1 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -181,10 +181,13 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config) (*stat context.GetHash = vmTestBlockHash evm := vm.NewEVM(context, statedb, config, vmconfig) - gaspool := new(core.GasPool) - gaspool.AddGas(block.GasLimit()) + gaspool := new(core.GasPool).AddGas(block.GasLimit()) + var gp1559 *core.GasPool + if config.IsEIP1559(block.Number()) { + gp1559 = new(core.GasPool).AddGas(params.MaxGasEIP1559) + } snapshot := statedb.Snapshot() - if _, _, _, err := core.ApplyMessage(evm, msg, gaspool); err != nil { + if _, _, _, err := core.ApplyMessage(evm, msg, gaspool, gp1559); err != nil { statedb.RevertToSnapshot(snapshot) } // Commit block