github.com/theQRL/go-zond@v0.1.1/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/theQRL/go-zond/common"
    24  	"github.com/theQRL/go-zond/common/math"
    25  	"github.com/theQRL/go-zond/core/txpool"
    26  	"github.com/theQRL/go-zond/core/types"
    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 *big.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 *big.Int) (*txWithMinerFee, error) {
    40  	tip := new(big.Int).Set(tx.GasTipCap)
    41  	if baseFee != nil {
    42  		if tx.GasFeeCap.Cmp(baseFee) < 0 {
    43  			return nil, types.ErrGasFeeCapTooLow
    44  		}
    45  		tip = math.BigMin(tx.GasTipCap, new(big.Int).Sub(tx.GasFeeCap, baseFee))
    46  	}
    47  	return &txWithMinerFee{
    48  		tx:   tx,
    49  		from: from,
    50  		fees: tip,
    51  	}, nil
    52  }
    53  
    54  // txByPriceAndTime implements both the sort and the heap interface, making it useful
    55  // for all at once sorting as well as individually adding and removing elements.
    56  type txByPriceAndTime []*txWithMinerFee
    57  
    58  func (s txByPriceAndTime) Len() int { return len(s) }
    59  func (s txByPriceAndTime) Less(i, j int) bool {
    60  	// If the prices are equal, use the time the transaction was first seen for
    61  	// deterministic sorting
    62  	cmp := s[i].fees.Cmp(s[j].fees)
    63  	if cmp == 0 {
    64  		return s[i].tx.Time.Before(s[j].tx.Time)
    65  	}
    66  	return cmp > 0
    67  }
    68  func (s txByPriceAndTime) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
    69  
    70  func (s *txByPriceAndTime) Push(x interface{}) {
    71  	*s = append(*s, x.(*txWithMinerFee))
    72  }
    73  
    74  func (s *txByPriceAndTime) Pop() interface{} {
    75  	old := *s
    76  	n := len(old)
    77  	x := old[n-1]
    78  	old[n-1] = nil
    79  	*s = old[0 : n-1]
    80  	return x
    81  }
    82  
    83  // transactionsByPriceAndNonce represents a set of transactions that can return
    84  // transactions in a profit-maximizing sorted order, while supporting removing
    85  // entire batches of transactions for non-executable accounts.
    86  type transactionsByPriceAndNonce struct {
    87  	txs     map[common.Address][]*txpool.LazyTransaction // Per account nonce-sorted list of transactions
    88  	heads   txByPriceAndTime                             // Next transaction for each unique account (price heap)
    89  	signer  types.Signer                                 // Signer for the set of transactions
    90  	baseFee *big.Int                                     // Current base fee
    91  }
    92  
    93  // newTransactionsByPriceAndNonce creates a transaction set that can retrieve
    94  // price sorted transactions in a nonce-honouring way.
    95  //
    96  // Note, the input map is reowned so the caller should not interact any more with
    97  // if after providing it to the constructor.
    98  func newTransactionsByPriceAndNonce(signer types.Signer, txs map[common.Address][]*txpool.LazyTransaction, baseFee *big.Int) *transactionsByPriceAndNonce {
    99  	// Initialize a price and received time based heap with the head transactions
   100  	heads := make(txByPriceAndTime, 0, len(txs))
   101  	for from, accTxs := range txs {
   102  		wrapped, err := newTxWithMinerFee(accTxs[0], from, baseFee)
   103  		if err != nil {
   104  			delete(txs, from)
   105  			continue
   106  		}
   107  		heads = append(heads, wrapped)
   108  		txs[from] = accTxs[1:]
   109  	}
   110  	heap.Init(&heads)
   111  
   112  	// Assemble and return the transaction set
   113  	return &transactionsByPriceAndNonce{
   114  		txs:     txs,
   115  		heads:   heads,
   116  		signer:  signer,
   117  		baseFee: baseFee,
   118  	}
   119  }
   120  
   121  // Peek returns the next transaction by price.
   122  func (t *transactionsByPriceAndNonce) Peek() *txpool.LazyTransaction {
   123  	if len(t.heads) == 0 {
   124  		return nil
   125  	}
   126  	return t.heads[0].tx
   127  }
   128  
   129  // Shift replaces the current best head with the next one from the same account.
   130  func (t *transactionsByPriceAndNonce) Shift() {
   131  	acc := t.heads[0].from
   132  	if txs, ok := t.txs[acc]; ok && len(txs) > 0 {
   133  		if wrapped, err := newTxWithMinerFee(txs[0], acc, t.baseFee); err == nil {
   134  			t.heads[0], t.txs[acc] = wrapped, txs[1:]
   135  			heap.Fix(&t.heads, 0)
   136  			return
   137  		}
   138  	}
   139  	heap.Pop(&t.heads)
   140  }
   141  
   142  // Pop removes the best transaction, *not* replacing it with the next one from
   143  // the same account. This should be used when a transaction cannot be executed
   144  // and hence all subsequent ones should be discarded from the same account.
   145  func (t *transactionsByPriceAndNonce) Pop() {
   146  	heap.Pop(&t.heads)
   147  }