github.com/MetalBlockchain/subnet-evm@v0.6.3/miner/ordering.go (about)

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