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 }