Skip to content

Commit

Permalink
eth, miner: fix enforcing the minimum miner tip (ethereum#28933)
Browse files Browse the repository at this point in the history
* eth, miner: fix enforcing the minimum miner tip

* ethclient/simulated: fix failing test due the min tip change

* accounts/abi/bind: fix simulater gas tip issue
  • Loading branch information
karalabe authored Feb 6, 2024
1 parent 0b5d8d2 commit 16ce7bf
Show file tree
Hide file tree
Showing 8 changed files with 53 additions and 13 deletions.
2 changes: 1 addition & 1 deletion accounts/abi/bind/util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ func TestWaitDeployed(t *testing.T) {

// Create the transaction
head, _ := backend.Client().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.LatestSignerForChainID(big.NewInt(1337)), testKey)
Expand Down
1 change: 1 addition & 0 deletions eth/api_miner.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
4 changes: 2 additions & 2 deletions ethclient/simulated/backend_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func newTx(sim *Backend, key *ecdsa.PrivateKey) (*types.Transaction, error) {

// create a signed transaction to send
head, _ := client.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))
addr := crypto.PubkeyToAddress(key.PublicKey)
chainid, _ := client.ChainID(context.Background())
nonce, err := client.PendingNonceAt(context.Background(), addr)
Expand All @@ -62,7 +62,7 @@ func newTx(sim *Backend, key *ecdsa.PrivateKey) (*types.Transaction, error) {
tx := types.NewTx(&types.DynamicFeeTx{
ChainID: chainid,
Nonce: nonce,
GasTipCap: big.NewInt(1),
GasTipCap: big.NewInt(params.GWei),
GasFeeCap: gasPrice,
Gas: 21000,
To: &addr,
Expand Down
16 changes: 16 additions & 0 deletions ethclient/simulated/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
package simulated

import (
"math/big"

"github.com/ethereum/go-ethereum/eth/ethconfig"
"github.com/ethereum/go-ethereum/node"
)
Expand All @@ -37,3 +39,17 @@ func WithCallGasLimit(gaslimit uint64) func(nodeConf *node.Config, ethConf *ethc
ethConf.RPCGasCap = gaslimit
}
}

// WithMinerMinTip configures the simulated backend to require a specific minimum
// gas tip for a transaction to be included.
//
// 0 is not possible as a live Geth node would reject that due to DoS protection,
// so the simulated backend will replicate that behavior for consisntency.
func WithMinerMinTip(tip *big.Int) func(nodeConf *node.Config, ethConf *ethconfig.Config) {
if tip == nil || tip.Cmp(new(big.Int)) <= 0 {
panic("invalid miner minimum tip")
}
return func(nodeConf *node.Config, ethConf *ethconfig.Config) {
ethConf.Miner.GasPrice = tip
}
}
5 changes: 5 additions & 0 deletions miner/miner.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,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)
Expand Down
6 changes: 3 additions & 3 deletions miner/ordering.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
4 changes: 2 additions & 2 deletions miner/ordering_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,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()
}
Expand Down Expand Up @@ -170,7 +170,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()
}
Expand Down
28 changes: 23 additions & 5 deletions miner/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,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
Expand Down Expand Up @@ -251,6 +252,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),
Expand Down Expand Up @@ -327,6 +329,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 {
Expand Down Expand Up @@ -554,7 +563,7 @@ func (w *worker) mainLoop() {
}
txset := newTransactionsByPriceAndNonce(w.current.signer, txs, w.current.header.BaseFee)
tcount := w.current.tcount
w.commitTransactions(w.current, txset, nil)
w.commitTransactions(w.current, txset, nil, new(big.Int))

// Only update the snapshot if any new transactions were added
// to the pending block
Expand Down Expand Up @@ -792,7 +801,7 @@ func (w *worker) applyTransaction(env *environment, tx *types.Transaction) (*typ
return receipt, err
}

func (w *worker) commitTransactions(env *environment, txs *transactionsByPriceAndNonce, interrupt *atomic.Int32) error {
func (w *worker) commitTransactions(env *environment, txs *transactionsByPriceAndNonce, interrupt *atomic.Int32, minTip *big.Int) error {
gasLimit := env.header.GasLimit
if env.gasPool == nil {
env.gasPool = new(core.GasPool).AddGas(gasLimit)
Expand All @@ -812,7 +821,7 @@ func (w *worker) commitTransactions(env *environment, txs *transactionsByPriceAn
break
}
// Retrieve the next transaction and abort if all done.
ltx := txs.Peek()
ltx, tip := txs.Peek()
if ltx == nil {
break
}
Expand All @@ -827,6 +836,11 @@ func (w *worker) commitTransactions(env *environment, txs *transactionsByPriceAn
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 {
Expand Down Expand Up @@ -997,15 +1011,19 @@ func (w *worker) fillTransactions(interrupt *atomic.Int32, env *environment) err
}

// Fill the block with all available pending transactions.
w.mu.RLock()
tip := w.tip
w.mu.RUnlock()

if len(localTxs) > 0 {
txs := newTransactionsByPriceAndNonce(env.signer, localTxs, env.header.BaseFee)
if err := w.commitTransactions(env, txs, interrupt); err != nil {
if err := w.commitTransactions(env, txs, interrupt, new(big.Int)); err != nil {
return err
}
}
if len(remoteTxs) > 0 {
txs := newTransactionsByPriceAndNonce(env.signer, remoteTxs, env.header.BaseFee)
if err := w.commitTransactions(env, txs, interrupt); err != nil {
if err := w.commitTransactions(env, txs, interrupt, tip); err != nil {
return err
}
}
Expand Down

0 comments on commit 16ce7bf

Please sign in to comment.