github.com/ethereum/go-ethereum@v1.14.3/miner/ordering.go (about)

     1  // Copyright 2014 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package miner
    18  
    19  import (
    20  	"container/heap"
    21  	"math/big"
    22  
    23  	"github.com/ethereum/go-ethereum/common"
    24  	"github.com/ethereum/go-ethereum/core/txpool"
    25  	"github.com/ethereum/go-ethereum/core/types"
    26  	"github.com/holiman/uint256"
    27  )
    28  
    29  // txWithMinerFee wraps a transaction with its gas price or effective miner gasTipCap
    30  type txWithMinerFee struct {
    31  	tx   *txpool.LazyTransaction
    32  	from common.Address
    33  	fees *uint256.Int
    34  }
    35  
    36  // newTxWithMinerFee creates a wrapped transaction, calculating the effective
    37  // miner gasTipCap if a base fee is provided.
    38  // Returns error in case of a negative effective miner gasTipCap.
    39  func newTxWithMinerFee(tx *txpool.LazyTransaction, from common.Address, baseFee *uint256.Int) (*txWithMinerFee, error) {
    40  	tip := new(uint256.Int).Set(tx.GasTipCap)
    41  	if baseFee != nil {
    42  		if tx.GasFeeCap.Cmp(baseFee) < 0 {
    43  			return nil, types.ErrGasFeeCapTooLow
    44  		}
    45  		tip = new(uint256.Int).Sub(tx.GasFeeCap, baseFee)
    46  		if tip.Gt(tx.GasTipCap) {
    47  			tip = tx.GasTipCap
    48  		}
    49  	}
    50  	return &txWithMinerFee{
    51  		tx:   tx,
    52  		from: from,
    53  		fees: tip,
    54  	}, nil
    55  }
    56  
    57  // txByPriceAndTime implements both the sort and the heap interface, making it useful
    58  // for all at once sorting as well as individually adding and removing elements.
    59  type txByPriceAndTime []*txWithMinerFee
    60  
    61  func (s txByPriceAndTime) Len() int { return len(s) }
    62  func (s txByPriceAndTime) Less(i, j int) bool {
    63  	// If the prices are equal, use the time the transaction was first seen for
    64  	// deterministic sorting
    65  	cmp := s[i].fees.Cmp(s[j].fees)
    66  	if cmp == 0 {
    67  		return s[i].tx.Time.Before(s[j].tx.Time)
    68  	}
    69  	return cmp > 0
    70  }
    71  func (s txByPriceAndTime) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
    72  
    73  func (s *txByPriceAndTime) Push(x interface{}) {
    74  	*s = append(*s, x.(*txWithMinerFee))
    75  }
    76  
    77  func (s *txByPriceAndTime) Pop() interface{} {
    78  	old := *s
    79  	n := len(old)
    80  	x := old[n-1]
    81  	old[n-1] = nil
    82  	*s = old[0 : n-1]
    83  	return x
    84  }
    85  
    86  // transactionsByPriceAndNonce represents a set of transactions that can return
    87  // transactions in a profit-maximizing sorted order, while supporting removing
    88  // entire batches of transactions for non-executable accounts.
    89  type transactionsByPriceAndNonce struct {
    90  	txs     map[common.Address][]*txpool.LazyTransaction // Per account nonce-sorted list of transactions
    91  	heads   txByPriceAndTime                             // Next transaction for each unique account (price heap)
    92  	signer  types.Signer                                 // Signer for the set of transactions
    93  	baseFee *uint256.Int                                 // Current base fee
    94  }
    95  
    96  // newTransactionsByPriceAndNonce creates a transaction set that can retrieve
    97  // price sorted transactions in a nonce-honouring way.
    98  //
    99  // Note, the input map is reowned so the caller should not interact any more with
   100  // if after providing it to the constructor.
   101  func newTransactionsByPriceAndNonce(signer types.Signer, txs map[common.Address][]*txpool.LazyTransaction, baseFee *big.Int) *transactionsByPriceAndNonce {
   102  	// Convert the basefee from header format to uint256 format
   103  	var baseFeeUint *uint256.Int
   104  	if baseFee != nil {
   105  		baseFeeUint = uint256.MustFromBig(baseFee)
   106  	}
   107  	// Initialize a price and received time based heap with the head transactions
   108  	heads := make(txByPriceAndTime, 0, len(txs))
   109  	for from, accTxs := range txs {
   110  		wrapped, err := newTxWithMinerFee(accTxs[0], from, baseFeeUint)
   111  		if err != nil {
   112  			delete(txs, from)
   113  			continue
   114  		}
   115  		heads = append(heads, wrapped)
   116  		txs[from] = accTxs[1:]
   117  	}
   118  	heap.Init(&heads)
   119  
   120  	// Assemble and return the transaction set
   121  	return &transactionsByPriceAndNonce{
   122  		txs:     txs,
   123  		heads:   heads,
   124  		signer:  signer,
   125  		baseFee: baseFeeUint,
   126  	}
   127  }
   128  
   129  // Peek returns the next transaction by price.
   130  func (t *transactionsByPriceAndNonce) Peek() (*txpool.LazyTransaction, *uint256.Int) {
   131  	if len(t.heads) == 0 {
   132  		return nil, nil
   133  	}
   134  	return t.heads[0].tx, t.heads[0].fees
   135  }
   136  
   137  // Shift replaces the current best head with the next one from the same account.
   138  func (t *transactionsByPriceAndNonce) Shift() {
   139  	acc := t.heads[0].from
   140  	if txs, ok := t.txs[acc]; ok && len(txs) > 0 {
   141  		if wrapped, err := newTxWithMinerFee(txs[0], acc, t.baseFee); err == nil {
   142  			t.heads[0], t.txs[acc] = wrapped, txs[1:]
   143  			heap.Fix(&t.heads, 0)
   144  			return
   145  		}
   146  	}
   147  	heap.Pop(&t.heads)
   148  }
   149  
   150  // Pop removes the best transaction, *not* replacing it with the next one from
   151  // the same account. This should be used when a transaction cannot be executed
   152  // and hence all subsequent ones should be discarded from the same account.
   153  func (t *transactionsByPriceAndNonce) Pop() {
   154  	heap.Pop(&t.heads)
   155  }
   156  
   157  // Empty returns if the price heap is empty. It can be used to check it simpler
   158  // than calling peek and checking for nil return.
   159  func (t *transactionsByPriceAndNonce) Empty() bool {
   160  	return len(t.heads) == 0
   161  }
   162  
   163  // Clear removes the entire content of the heap.
   164  func (t *transactionsByPriceAndNonce) Clear() {
   165  	t.heads, t.txs = nil, nil
   166  }