From 470da15e0b690a3f6a359cb1e80462924256263e Mon Sep 17 00:00:00 2001 From: Ian Norden Date: Fri, 8 Nov 2019 09:45:50 -0600 Subject: [PATCH 1/6] gas pool/trx execution changes to core --- core/chain_makers.go | 16 ++++--- core/evm.go | 1 + core/state_prefetcher.go | 10 +++-- core/state_processor.go | 10 +++-- core/state_transition.go | 97 +++++++++++++++++++++++++++++++++++----- core/tx_pool.go | 4 ++ core/vm/evm.go | 1 + 7 files changed, 116 insertions(+), 23 deletions(-) diff --git a/core/chain_makers.go b/core/chain_makers.go index 0b0fcdb4aa39..5b0f363db840 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 @@ -51,7 +52,7 @@ type BlockGen struct { // SetCoinbase sets the coinbase of the generated block. // It can be called at most once. func (b *BlockGen) SetCoinbase(addr common.Address) { - if b.gasPool != nil { + if b.gasPool != nil || b.gasPool1559 != nil { if len(b.txs) > 0 { panic("coinbase must be set before adding transactions") } @@ -59,6 +60,7 @@ func (b *BlockGen) SetCoinbase(addr common.Address) { } b.header.Coinbase = addr b.gasPool = new(GasPool).AddGas(b.header.GasLimit) + b.gasPool1559 = new(GasPool).AddGas(params.MaxGasEIP1559) } // SetExtra sets the extra data field of the generated block. @@ -99,11 +101,11 @@ func (b *BlockGen) AddTx(tx *types.Transaction) { // added. If contract code relies on the BLOCKHASH instruction, // the block in chain will be returned. func (b *BlockGen) AddTxWithChain(bc *BlockChain, tx *types.Transaction) { - if b.gasPool == nil { + if b.gasPool == nil || b.gasPool1559 == nil { b.SetCoinbase(common.Address{}) } 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..c2b3891cae53 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -50,6 +50,7 @@ The state transitioning model does all the necessary work to work out a valid ne */ type StateTransition struct { gp *GasPool + gp1559 *GasPool msg Message gas uint64 gasPrice *big.Int @@ -58,6 +59,7 @@ type StateTransition struct { data []byte state vm.StateDB evm *vm.EVM + isEIP1559 bool } // Message represents a message sent to a contract. @@ -116,15 +118,21 @@ 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 { +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 + // check that msg doesn't try to set both legacy and 1559 params + // check that legacy has legacy params set + // reject 1559 trxs if we are before the 1559 fork blocknumber return &StateTransition{ - gp: gp, - evm: evm, - msg: msg, - gasPrice: msg.GasPrice(), - value: msg.Value(), - data: msg.Data(), - state: evm.StateDB, + gp: gp, + gp1559: gp1559, + evm: evm, + msg: msg, + gasPrice: msg.GasPrice(), + value: msg.Value(), + data: msg.Data(), + state: evm.StateDB, + isEIP1559: isEIP1559, } } @@ -135,8 +143,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 +165,33 @@ 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 { + // any reason we can't set st.gasPrice to this? + gasPrice := new(big.Int).Add(st.evm.BaseFee, st.msg.GasPremium()) + if gasPrice.Cmp(st.msg.FeeCap()) > 0 { + gasPrice.Set(st.msg.FeeCap()) + } + mgval := new(big.Int).Mul(new(big.Int).SetUint64(st.msg.Gas()), gasPrice) + 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 +216,10 @@ func (st *StateTransition) preCheck() error { return ErrNonceTooLow } } + // If we are past the EIP1559 finalization block and this transaction does not conform with EIP1559, throw an error + if st.evm.ChainConfig().IsEIP1559Finalized(st.evm.BlockNumber) && !st.isEIP1559 { + return ErrTxNotEIP1559 + } return st.buyGas() } @@ -230,12 +269,29 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo } } st.refundGas() + if st.isEIP1559 { // if we can set st.gasPrice to the calculated eip1559 gasPrice in buyGas then we don't need this + gasPrice := new(big.Int).Add(st.evm.BaseFee, st.msg.GasPremium()) + if gasPrice.Cmp(st.msg.FeeCap()) > 0 { + gasPrice.Set(st.msg.FeeCap()) + } + st.state.AddBalance(st.evm.Coinbase, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), gasPrice)) + + 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 +308,27 @@ 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 + + // Return ETH for remaining gas, exchanged at the original rate. + gasPrice := new(big.Int).Add(st.evm.BaseFee, st.msg.GasPremium()) + if gasPrice.Cmp(st.msg.FeeCap()) > 0 { + gasPrice.Set(st.msg.FeeCap()) + } + remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gas), gasPrice) + 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..1ead0b72c9f4 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -76,6 +76,10 @@ 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 passed the EIP1559 finalized block height + // and the input transaction does not conform to with EIP1559 + ErrTxNotEIP1559 = errors.New("transaction does not conform with EIP1559") ) var ( 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 From 4c6d08c3ce075372ddce7c9d4aec7ef55ac974fb Mon Sep 17 00:00:00 2001 From: Ian Norden Date: Tue, 12 Nov 2019 14:19:15 -0600 Subject: [PATCH 2/6] apply gas pool/trx execution changes across pkgs --- accounts/abi/bind/backends/simulated.go | 6 ++++- cmd/geth/retesteth.go | 17 +++++++++++-- eth/api_tracer.go | 26 ++++++++++++++++---- eth/handler_test.go | 4 ++-- eth/tracers/tracers_test.go | 10 ++++++-- internal/ethapi/api.go | 6 ++++- les/odr_test.go | 12 ++++++++-- light/odr_test.go | 6 ++++- miner/worker.go | 32 ++++++++++++++++++------- tests/state_test_util.go | 9 ++++--- 10 files changed, 101 insertions(+), 27 deletions(-) diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index 801d4725a9b3..a9091052d827 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -319,8 +319,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. 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/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..226db972e0df 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -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 } 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..03200f386fa1 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 @@ -704,7 +705,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 @@ -724,10 +725,28 @@ func (w *worker) commitTransactions(txs *types.TransactionsByPriceAndNonce, coin if 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) + } 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 + var gp *core.GasPool + if tx.GasPrice() == nil && tx.GasPremium() != nil && tx.FeeCap() != nil { + gp = w.current.gp1559 + } else if tx.GasPremium() == nil && tx.FeeCap() == nil && tx.GasPrice() != nil { + gp = w.current.gasPool + } else { + 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 +756,7 @@ 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) + ratio := float64(w.current.header.GasLimit-gp.Gas()) / float64(w.current.header.GasLimit) if ratio < 0.1 { ratio = 0.1 } @@ -749,13 +768,8 @@ 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 { + if gp.Gas() < params.TxGas { + log.Trace("Not enough gas for further transactions", "have", gp, "want", params.TxGas) break } // Error may be ignored here. The error has already been checked 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 From f2050e348b2a97cd19057ace7eee7565457d2477 Mon Sep 17 00:00:00 2001 From: Ian Norden Date: Tue, 19 Nov 2019 13:23:20 -0600 Subject: [PATCH 3/6] fix refund and coinbase credit --- core/state_transition.go | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/core/state_transition.go b/core/state_transition.go index c2b3891cae53..a6478e64e76e 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") ) /* @@ -172,11 +173,12 @@ func (st *StateTransition) buyGas() error { } func (st *StateTransition) buyGasEIP1559() error { - // any reason we can't set st.gasPrice to this? + // gasPrice = min(BASEFEE + tx.fee_premium, tx.fee_cap) gasPrice := new(big.Int).Add(st.evm.BaseFee, st.msg.GasPremium()) if gasPrice.Cmp(st.msg.FeeCap()) > 0 { gasPrice.Set(st.msg.FeeCap()) } + // tx.origin pays gasPrice * tx.gas mgval := new(big.Int).Mul(new(big.Int).SetUint64(st.msg.Gas()), gasPrice) if st.state.GetBalance(st.msg.From()).Cmp(mgval) < 0 { return errInsufficientBalanceForGas @@ -269,11 +271,22 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo } } st.refundGas() - if st.isEIP1559 { // if we can set st.gasPrice to the calculated eip1559 gasPrice in buyGas then we don't need this + if st.isEIP1559 { gasPrice := new(big.Int).Add(st.evm.BaseFee, st.msg.GasPremium()) if gasPrice.Cmp(st.msg.FeeCap()) > 0 { gasPrice.Set(st.msg.FeeCap()) } + // block.coinbase gains (gasprice - BASEFEE) * gasused + coinBaseCredit := new(big.Int).Mul(new(big.Int).Sub(gasPrice, 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, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), gasPrice)) return ret, st.gasUsed(), vmerr != nil, err @@ -316,12 +329,15 @@ func (st *StateTransition) refundGasEIP1559() { } st.gas += refund - // Return ETH for remaining gas, exchanged at the original rate. + // 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())) + + // gasPrice = min(BASEFEE + tx.fee_premium, tx.fee_cap) gasPrice := new(big.Int).Add(st.evm.BaseFee, st.msg.GasPremium()) if gasPrice.Cmp(st.msg.FeeCap()) > 0 { gasPrice.Set(st.msg.FeeCap()) } - remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gas), gasPrice) + remaining := new(big.Int).Mul(gasPrice, txGasSubUsed) st.state.AddBalance(st.msg.From(), remaining) // Also return remaining gas to the block gas counter so it is From 1d773884115e8d75318bdf9d2020880927cd3faa Mon Sep 17 00:00:00 2001 From: Ian Norden Date: Tue, 19 Nov 2019 13:51:58 -0600 Subject: [PATCH 4/6] add guards to backends/simulated.go callContract and SendTransaction --- accounts/abi/bind/backends/simulated.go | 38 ++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index a9091052d827..d7953dcb89a9 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, fmt.Errorf("after block %d EIP1559 is finalized and transactions must contain a GasPremium and FeeCap and not contain a GasPrice", b.config.EIP1559FinalizedBlock.Uint64()) + } + if !b.config.IsEIP1559(block.Number()) && call.GasPremium != nil || call.FeeCap != nil || call.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.config.EIP1559Block.Uint64()) + } + if call.GasPrice != nil && (call.GasPremium != nil || call.FeeCap != nil) { + return nil, 0, false, errors.New("if GasPrice is set, GasPremium and FeeCap must not be set") + } + 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 { @@ -333,6 +349,26 @@ 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 fmt.Errorf("after block %d EIP1559 is finalized and transactions must contain a GasPremium and FeeCap and not contain a GasPrice", b.config.EIP1559FinalizedBlock.Uint64()) + } + if !b.config.IsEIP1559(b.blockchain.CurrentBlock().Number()) && tx.GasPremium() != nil || tx.FeeCap() != nil || tx.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.config.EIP1559Block.Uint64()) + } + if tx.GasPrice() != nil && (tx.GasPremium() != nil || tx.FeeCap() != nil) { + return errors.New("if GasPrice is set, GasPremium and FeeCap must not be set") + } + if tx.FeeCap() != nil && tx.GasPremium() == nil { + return errors.New("if FeeCap is set, GasPremium must be set") + } + if tx.GasPremium() != nil && tx.FeeCap() == nil { + return errors.New("if GasPremium is set, FeeCap must be set") + } + if tx.GasPrice() == nil && tx.GasPremium() == nil { + return errors.New("either GasPrice or GasPremium and FeeCap need to be set") + } + sender, err := types.Sender(types.NewEIP155Signer(b.config.ChainID), tx) if err != nil { panic(fmt.Errorf("invalid transaction: %v", err)) From 52d5c08c424c492c122cec0cc6e8c21855386c47 Mon Sep 17 00:00:00 2001 From: Ian Norden Date: Wed, 20 Nov 2019 16:26:10 -0600 Subject: [PATCH 5/6] simplify calculations in state_transition.go; add guards and derive gasPrice in TxPool.validateTx --- accounts/abi/bind/backends/simulated.go | 30 ++++------ core/chain_makers.go | 8 ++- core/state_transition.go | 77 ++++++++++++++----------- core/tx_pool.go | 48 ++++++++++++++- internal/ethapi/api.go | 37 ++++++------ 5 files changed, 121 insertions(+), 79 deletions(-) diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index d7953dcb89a9..7a7ab8d85290 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -300,14 +300,14 @@ func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMs 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. // EIP1559 guards - if b.config.IsEIP1559Finalized(block.Number()) && call.GasPremium == nil || call.FeeCap == nil || call.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.config.EIP1559FinalizedBlock.Uint64()) + 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, fmt.Errorf("before block %d EIP1559 is not activated and transactions must contain a GasPrice and not contain a GasPremium or FeeCap", b.config.EIP1559Block.Uint64()) + 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, errors.New("if GasPrice is set, GasPremium and FeeCap must not be set") + 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") @@ -350,23 +350,17 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa defer b.mu.Unlock() // EIP1559 guards - if b.config.IsEIP1559Finalized(b.blockchain.CurrentBlock().Number()) && tx.GasPremium() == nil || tx.FeeCap() == nil || tx.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.config.EIP1559FinalizedBlock.Uint64()) + 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 fmt.Errorf("before block %d EIP1559 is not activated and transactions must contain a GasPrice and not contain a GasPremium or FeeCap", b.config.EIP1559Block.Uint64()) + 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 errors.New("if GasPrice is set, GasPremium and FeeCap must not be set") + return core.ErrTxSetsLegacyAndEIP1559Fields } - if tx.FeeCap() != nil && tx.GasPremium() == nil { - return errors.New("if FeeCap is set, GasPremium must be set") - } - if tx.GasPremium() != nil && tx.FeeCap() == nil { - return errors.New("if GasPremium is set, FeeCap must be set") - } - if tx.GasPrice() == nil && tx.GasPremium() == nil { - return errors.New("either GasPrice or GasPremium and FeeCap need to be set") + if tx.GasPrice() == nil && (tx.GasPremium() == nil || tx.FeeCap() == nil) { + return core.ErrMissingGasFields } sender, err := types.Sender(types.NewEIP155Signer(b.config.ChainID), tx) diff --git a/core/chain_makers.go b/core/chain_makers.go index 5b0f363db840..6a3363c41c66 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -52,7 +52,7 @@ type BlockGen struct { // SetCoinbase sets the coinbase of the generated block. // It can be called at most once. func (b *BlockGen) SetCoinbase(addr common.Address) { - if b.gasPool != nil || b.gasPool1559 != nil { + if b.gasPool != nil { if len(b.txs) > 0 { panic("coinbase must be set before adding transactions") } @@ -60,7 +60,6 @@ func (b *BlockGen) SetCoinbase(addr common.Address) { } b.header.Coinbase = addr b.gasPool = new(GasPool).AddGas(b.header.GasLimit) - b.gasPool1559 = new(GasPool).AddGas(params.MaxGasEIP1559) } // SetExtra sets the extra data field of the generated block. @@ -101,9 +100,12 @@ func (b *BlockGen) AddTx(tx *types.Transaction) { // added. If contract code relies on the BLOCKHASH instruction, // the block in chain will be returned. func (b *BlockGen) AddTxWithChain(bc *BlockChain, tx *types.Transaction) { - if b.gasPool == nil || b.gasPool1559 == nil { + 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.gasPool1559, b.statedb, b.header, tx, &b.header.GasUsed, vm.Config{}) if err != nil { diff --git a/core/state_transition.go b/core/state_transition.go index a6478e64e76e..9998d849a0c9 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -50,17 +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 - gp1559 *GasPool - msg Message - gas uint64 - gasPrice *big.Int - initialGas uint64 - value *big.Int - data []byte - state vm.StateDB - evm *vm.EVM - isEIP1559 bool + 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. @@ -121,10 +122,7 @@ 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, gp1559 *GasPool) *StateTransition { isEIP1559 := evm.ChainConfig().IsEIP1559(evm.BlockNumber) && msg.GasPremium() != nil && msg.FeeCap() != nil && evm.BaseFee != nil && gp1559 != nil - // check that msg doesn't try to set both legacy and 1559 params - // check that legacy has legacy params set - // reject 1559 trxs if we are before the 1559 fork blocknumber - return &StateTransition{ + st := &StateTransition{ gp: gp, gp1559: gp1559, evm: evm, @@ -135,6 +133,14 @@ func NewStateTransition(evm *vm.EVM, msg Message, gp, gp1559 *GasPool) *StateTra 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 @@ -173,13 +179,8 @@ func (st *StateTransition) buyGas() error { } func (st *StateTransition) buyGasEIP1559() error { - // gasPrice = min(BASEFEE + tx.fee_premium, tx.fee_cap) - gasPrice := new(big.Int).Add(st.evm.BaseFee, st.msg.GasPremium()) - if gasPrice.Cmp(st.msg.FeeCap()) > 0 { - gasPrice.Set(st.msg.FeeCap()) - } // tx.origin pays gasPrice * tx.gas - mgval := new(big.Int).Mul(new(big.Int).SetUint64(st.msg.Gas()), gasPrice) + 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 } @@ -218,10 +219,26 @@ func (st *StateTransition) preCheck() error { return ErrNonceTooLow } } - // If we are past the EIP1559 finalization block and this transaction does not conform with EIP1559, throw an error + // 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() } @@ -272,12 +289,8 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo } st.refundGas() if st.isEIP1559 { - gasPrice := new(big.Int).Add(st.evm.BaseFee, st.msg.GasPremium()) - if gasPrice.Cmp(st.msg.FeeCap()) > 0 { - gasPrice.Set(st.msg.FeeCap()) - } // block.coinbase gains (gasprice - BASEFEE) * gasused - coinBaseCredit := new(big.Int).Mul(new(big.Int).Sub(gasPrice, st.evm.BaseFee), new(big.Int).SetUint64(st.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 { @@ -287,7 +300,7 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo return nil, 0, vmerr != nil, errInsufficientCoinbaseBalance } } - st.state.AddBalance(st.evm.Coinbase, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), gasPrice)) + st.state.AddBalance(st.evm.Coinbase, coinBaseCredit) return ret, st.gasUsed(), vmerr != nil, err } @@ -331,13 +344,7 @@ func (st *StateTransition) refundGasEIP1559() { // 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())) - - // gasPrice = min(BASEFEE + tx.fee_premium, tx.fee_cap) - gasPrice := new(big.Int).Add(st.evm.BaseFee, st.msg.GasPremium()) - if gasPrice.Cmp(st.msg.FeeCap()) > 0 { - gasPrice.Set(st.msg.FeeCap()) - } - remaining := new(big.Int).Mul(gasPrice, txGasSubUsed) + 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 diff --git a/core/tx_pool.go b/core/tx_pool.go index 1ead0b72c9f4..db3c55ea4b82 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -77,9 +77,24 @@ var ( // making the transaction invalid, rather a DOS protection. ErrOversizedData = errors.New("oversized data") - // ErrTxNotEIP1559 is returned if we have passed the EIP1559 finalized block height + // ErrTxNotEIP1559 is returned if we have reached the EIP1559 finalized block height // and the input transaction does not conform to with EIP1559 - ErrTxNotEIP1559 = errors.New("transaction does not conform 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 ( @@ -514,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 @@ -534,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/internal/ethapi/api.go b/internal/ethapi/api.go index 226db972e0df..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") @@ -1395,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") @@ -1559,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") + return common.Hash{}, core.ErrTxSetsLegacyAndEIP1559Fields } - if tx.FeeCap() != nil && tx.GasPremium() == nil { - return common.Hash{}, errors.New("if FeeCap is set, GasPremium must be set") - } - 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) } From 1937670a37c41b1129ffb4d7783b1bd578dfec1c Mon Sep 17 00:00:00 2001 From: Ian Norden Date: Fri, 22 Nov 2019 13:31:52 -0600 Subject: [PATCH 6/6] worker.commitTransaction() calc ratio using MaxGasEIP1559 instead of header.GasLimit if trx is of type 1559 --- miner/worker.go | 66 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 55 insertions(+), 11 deletions(-) diff --git a/miner/worker.go b/miner/worker.go index 03200f386fa1..17d8974efb12 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -455,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() @@ -484,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(): @@ -722,12 +736,16 @@ 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 @@ -738,12 +756,37 @@ func (w *worker) commitTransactions(txs *types.TransactionsByPriceAndNonce, coin break } // Set which gasPool to use based on the type of transaction + eip1559 := false var gp *core.GasPool - if tx.GasPrice() == nil && tx.GasPremium() != nil && tx.FeeCap() != nil { + if w.chainConfig.IsEIP1559(w.current.header.Number) && tx.GasPrice() == nil && tx.GasPremium() != nil && tx.FeeCap() != nil { gp = w.current.gp1559 - } else if tx.GasPremium() == nil && tx.FeeCap() == nil && tx.GasPrice() != nil { + 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 } @@ -756,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-gp.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 } @@ -767,11 +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 gp.Gas() < params.TxGas { - log.Trace("Not enough gas for further transactions", "have", gp, "want", params.TxGas) - break - } + // Error may be ignored here. The error has already been checked // during transaction acceptance is the transaction pool. //