diff --git a/accounts/abi/bind/util_test.go b/accounts/abi/bind/util_test.go index a35e56a6a8..f58eb9ae84 100644 --- a/accounts/abi/bind/util_test.go +++ b/accounts/abi/bind/util_test.go @@ -29,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/params" ) var testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") @@ -64,7 +65,7 @@ func TestWaitDeployed(t *testing.T) { // Create the transaction head, _ := backend.HeaderByNumber(context.Background(), nil) // Should be child's, good enough - gasPrice := new(big.Int).Add(head.BaseFee, big.NewInt(1)) + gasPrice := new(big.Int).Add(head.BaseFee, big.NewInt(params.GWei)) tx := types.NewContractCreation(0, big.NewInt(0), test.gas, gasPrice, common.FromHex(test.code)) tx, _ = types.SignTx(tx, types.HomesteadSigner{}, testKey) diff --git a/eth/api_miner.go b/eth/api_miner.go index 477531d494..2fe296548a 100644 --- a/eth/api_miner.go +++ b/eth/api_miner.go @@ -64,6 +64,7 @@ func (api *MinerAPI) SetGasPrice(gasPrice hexutil.Big) bool { api.e.lock.Unlock() api.e.txPool.SetGasTip((*big.Int)(&gasPrice)) + api.e.Miner().SetGasTip((*big.Int)(&gasPrice)) return true } diff --git a/miner/miner.go b/miner/miner.go index cfc85ebfcb..03fa21edbf 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -219,6 +219,11 @@ func (miner *Miner) SetExtra(extra []byte) error { return nil } +func (miner *Miner) SetGasTip(tip *big.Int) error { + miner.worker.setGasTip(tip) + return nil +} + // SetRecommitInterval sets the interval for sealing work resubmitting. func (miner *Miner) SetRecommitInterval(interval time.Duration) { miner.worker.setRecommitInterval(interval) diff --git a/miner/ordering.go b/miner/ordering.go index 9777633510..828d53d241 100644 --- a/miner/ordering.go +++ b/miner/ordering.go @@ -119,11 +119,11 @@ func newTransactionsByPriceAndNonce(signer types.Signer, txs map[common.Address] } // Peek returns the next transaction by price. -func (t *transactionsByPriceAndNonce) Peek() *txpool.LazyTransaction { +func (t *transactionsByPriceAndNonce) Peek() (*txpool.LazyTransaction, *big.Int) { if len(t.heads) == 0 { - return nil + return nil, nil } - return t.heads[0].tx + return t.heads[0].tx, t.heads[0].fees } // Shift replaces the current best head with the next one from the same account. diff --git a/miner/ordering_test.go b/miner/ordering_test.go index 59d478274d..c2f08328db 100644 --- a/miner/ordering_test.go +++ b/miner/ordering_test.go @@ -102,7 +102,7 @@ func testTransactionPriceNonceSort(t *testing.T, baseFee *big.Int) { txset := newTransactionsByPriceAndNonce(signer, groups, baseFee) txs := types.Transactions{} - for tx := txset.Peek(); tx != nil; tx = txset.Peek() { + for tx, _ := txset.Peek(); tx != nil; tx, _ = txset.Peek() { txs = append(txs, tx.Tx) txset.Shift() } @@ -167,7 +167,7 @@ func TestTransactionTimeSort(t *testing.T) { txset := newTransactionsByPriceAndNonce(signer, groups, nil) txs := types.Transactions{} - for tx := txset.Peek(); tx != nil; tx = txset.Peek() { + for tx, _ := txset.Peek(); tx != nil; tx, _ = txset.Peek() { txs = append(txs, tx.Tx) txset.Shift() } diff --git a/miner/test_backend.go b/miner/test_backend.go index b2fa96b059..03447f446f 100644 --- a/miner/test_backend.go +++ b/miner/test_backend.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "math/big" "os" "sync" "sync/atomic" @@ -175,7 +176,7 @@ func (w *worker) mainLoopWithDelay(ctx context.Context, delay uint, opcodeDelay } txset := newTransactionsByPriceAndNonce(w.current.signer, txs, w.current.header.BaseFee) tcount := w.current.tcount - w.commitTransactions(w.current, txset, nil, context.Background()) + w.commitTransactions(w.current, txset, nil, new(big.Int), context.Background()) // Only update the snapshot if any new transactons were added // to the pending block @@ -587,7 +588,7 @@ mainloop: break } // Retrieve the next transaction and abort if all done. - ltx := txs.Peek() + ltx, _ := txs.Peek() if ltx == nil { breakCause = "all transactions has been included" break diff --git a/miner/worker.go b/miner/worker.go index 5b3c754f49..b134f83069 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -237,6 +237,7 @@ type worker struct { mu sync.RWMutex // The lock used to protect the coinbase and extra fields coinbase common.Address extra []byte + tip *big.Int // Minimum tip needed for non-local transaction to include them pendingMu sync.RWMutex pendingTasks map[common.Hash]*task @@ -295,6 +296,7 @@ func newWorker(config *Config, chainConfig *params.ChainConfig, engine consensus isLocalBlock: isLocalBlock, coinbase: config.Etherbase, extra: config.ExtraData, + tip: config.GasPrice, pendingTasks: make(map[common.Hash]*task), txsCh: make(chan core.NewTxsEvent, txChanSize), chainHeadCh: make(chan core.ChainHeadEvent, chainHeadChanSize), @@ -395,6 +397,13 @@ func (w *worker) setExtra(extra []byte) { w.extra = extra } +// setGasTip sets the minimum miner tip needed to include a non-local transaction. +func (w *worker) setGasTip(tip *big.Int) { + w.mu.Lock() + defer w.mu.Unlock() + w.tip = tip +} + // setRecommitInterval updates the interval for miner sealing work recommitting. func (w *worker) setRecommitInterval(interval time.Duration) { select { @@ -648,7 +657,7 @@ func (w *worker) mainLoop(ctx context.Context) { } txset := newTransactionsByPriceAndNonce(w.current.signer, txs, w.current.header.BaseFee) tcount := w.current.tcount - w.commitTransactions(w.current, txset, nil, context.Background()) + w.commitTransactions(w.current, txset, nil, new(big.Int), context.Background()) // Only update the snapshot if any new transactons were added // to the pending block @@ -908,7 +917,7 @@ func (w *worker) commitTransaction(env *environment, tx *types.Transaction, inte return receipt.Logs, nil } -func (w *worker) commitTransactions(env *environment, txs *transactionsByPriceAndNonce, interrupt *atomic.Int32, interruptCtx context.Context) error { +func (w *worker) commitTransactions(env *environment, txs *transactionsByPriceAndNonce, interrupt *atomic.Int32, minTip *big.Int, interruptCtx context.Context) error { gasLimit := env.header.GasLimit if env.gasPool == nil { env.gasPool = new(core.GasPool).AddGas(gasLimit) @@ -996,7 +1005,7 @@ mainloop: break } // Retrieve the next transaction and abort if all done. - ltx := txs.Peek() + ltx, tip := txs.Peek() if ltx == nil { breakCause = "all transactions has been included" break @@ -1012,6 +1021,11 @@ mainloop: txs.Pop() continue } + // If we don't receive enough tip for the next transaction, skip the account + if tip.Cmp(minTip) < 0 { + log.Trace("Not enough tip for transaction", "hash", ltx.Hash, "tip", tip, "needed", minTip) + break // If the next-best is too low, surely no better will be available + } // Transaction seems to fit, pull it up from the pool tx := ltx.Resolve() if tx == nil { @@ -1469,6 +1483,10 @@ func (w *worker) fillTransactions(ctx context.Context, interrupt *atomic.Int32, err error ) + w.mu.RLock() + tip := w.tip + w.mu.RUnlock() + if len(localTxs) > 0 { var txs *transactionsByPriceAndNonce @@ -1487,7 +1505,7 @@ func (w *worker) fillTransactions(ctx context.Context, interrupt *atomic.Int32, }) tracing.Exec(ctx, "", "worker.LocalCommitTransactions", func(ctx context.Context, span trace.Span) { - err = w.commitTransactions(env, txs, interrupt, interruptCtx) + err = w.commitTransactions(env, txs, interrupt, new(big.Int), interruptCtx) }) if err != nil { @@ -1515,7 +1533,7 @@ func (w *worker) fillTransactions(ctx context.Context, interrupt *atomic.Int32, }) tracing.Exec(ctx, "", "worker.RemoteCommitTransactions", func(ctx context.Context, span trace.Span) { - err = w.commitTransactions(env, txs, interrupt, interruptCtx) + err = w.commitTransactions(env, txs, interrupt, tip, interruptCtx) }) if err != nil {