3636 ErrUnexpectedProtection = errors .New ("transaction type does not supported EIP-155 protected signatures" )
3737 ErrInvalidTxType = errors .New ("transaction type not valid in this context" )
3838 ErrTxTypeNotSupported = errors .New ("transaction type not supported" )
39+ ErrFeeCapTooLow = errors .New ("fee cap less than base fee" )
3940 errEmptyTypedTx = errors .New ("empty typed transaction bytes" )
4041)
4142
@@ -299,6 +300,19 @@ func (tx *Transaction) Cost() *big.Int {
299300 return total
300301}
301302
303+ // EffectiveTip returns the effective miner tip for the given base fee.
304+ // Returns error in case of a negative effective miner tip.
305+ func (tx * Transaction ) EffectiveTip (baseFee * big.Int ) (* big.Int , error ) {
306+ if baseFee == nil {
307+ return tx .Tip (), nil
308+ }
309+ feeCap := tx .FeeCap ()
310+ if feeCap .Cmp (baseFee ) == - 1 {
311+ return nil , ErrFeeCapTooLow
312+ }
313+ return math .BigMin (tx .Tip (), feeCap .Sub (feeCap , baseFee )), nil
314+ }
315+
302316// RawSignatureValues returns the V, R, S signature values of the transaction.
303317// The return values should not be modified by the caller.
304318func (tx * Transaction ) RawSignatureValues () (v , r , s * big.Int ) {
@@ -400,24 +414,44 @@ func (s TxByNonce) Len() int { return len(s) }
400414func (s TxByNonce ) Less (i , j int ) bool { return s [i ].Nonce () < s [j ].Nonce () }
401415func (s TxByNonce ) Swap (i , j int ) { s [i ], s [j ] = s [j ], s [i ] }
402416
417+ // TxWithMinerFee wraps a transaction with its gas price or effective miner tip
418+ type TxWithMinerFee struct {
419+ tx * Transaction
420+ minerFee * big.Int
421+ }
422+
423+ // NewTxWithMinerFee creates a wrapped transaction, calculating the effective
424+ // miner tip if a base fee is provided.
425+ // Returns error in case of a negative effective miner tip.
426+ func NewTxWithMinerFee (tx * Transaction , baseFee * big.Int ) (* TxWithMinerFee , error ) {
427+ minerFee , err := tx .EffectiveTip (baseFee )
428+ if err != nil {
429+ return nil , err
430+ }
431+ return & TxWithMinerFee {
432+ tx : tx ,
433+ minerFee : minerFee ,
434+ }, nil
435+ }
436+
403437// TxByPriceAndTime implements both the sort and the heap interface, making it useful
404438// for all at once sorting as well as individually adding and removing elements.
405- type TxByPriceAndTime Transactions
439+ type TxByPriceAndTime [] * TxWithMinerFee
406440
407441func (s TxByPriceAndTime ) Len () int { return len (s ) }
408442func (s TxByPriceAndTime ) Less (i , j int ) bool {
409443 // If the prices are equal, use the time the transaction was first seen for
410444 // deterministic sorting
411- cmp := s [i ].GasPrice () .Cmp (s [j ].GasPrice () )
445+ cmp := s [i ].minerFee .Cmp (s [j ].minerFee )
412446 if cmp == 0 {
413- return s [i ].time .Before (s [j ].time )
447+ return s [i ].tx . time .Before (s [j ]. tx .time )
414448 }
415449 return cmp > 0
416450}
417451func (s TxByPriceAndTime ) Swap (i , j int ) { s [i ], s [j ] = s [j ], s [i ] }
418452
419453func (s * TxByPriceAndTime ) Push (x interface {}) {
420- * s = append (* s , x .(* Transaction ))
454+ * s = append (* s , x .(* TxWithMinerFee ))
421455}
422456
423457func (s * TxByPriceAndTime ) Pop () interface {} {
@@ -432,35 +466,39 @@ func (s *TxByPriceAndTime) Pop() interface{} {
432466// transactions in a profit-maximizing sorted order, while supporting removing
433467// entire batches of transactions for non-executable accounts.
434468type TransactionsByPriceAndNonce struct {
435- txs map [common.Address ]Transactions // Per account nonce-sorted list of transactions
436- heads TxByPriceAndTime // Next transaction for each unique account (price heap)
437- signer Signer // Signer for the set of transactions
469+ txs map [common.Address ]Transactions // Per account nonce-sorted list of transactions
470+ heads TxByPriceAndTime // Next transaction for each unique account (price heap)
471+ signer Signer // Signer for the set of transactions
472+ baseFee * big.Int // Current base fee
438473}
439474
440475// NewTransactionsByPriceAndNonce creates a transaction set that can retrieve
441476// price sorted transactions in a nonce-honouring way.
442477//
443478// Note, the input map is reowned so the caller should not interact any more with
444479// if after providing it to the constructor.
445- func NewTransactionsByPriceAndNonce (signer Signer , txs map [common.Address ]Transactions ) * TransactionsByPriceAndNonce {
480+ func NewTransactionsByPriceAndNonce (signer Signer , txs map [common.Address ]Transactions , baseFee * big. Int ) * TransactionsByPriceAndNonce {
446481 // Initialize a price and received time based heap with the head transactions
447482 heads := make (TxByPriceAndTime , 0 , len (txs ))
448483 for from , accTxs := range txs {
449- // Ensure the sender address is from the signer
450- if acc , _ := Sender (signer , accTxs [0 ]); acc != from {
484+ acc , _ := Sender (signer , accTxs [0 ])
485+ wrapped , err := NewTxWithMinerFee (accTxs [0 ], baseFee )
486+ // Remove transaction if sender doesn't match from, or if wrapping fails.
487+ if acc != from || err != nil {
451488 delete (txs , from )
452489 continue
453490 }
454- heads = append (heads , accTxs [ 0 ] )
491+ heads = append (heads , wrapped )
455492 txs [from ] = accTxs [1 :]
456493 }
457494 heap .Init (& heads )
458495
459496 // Assemble and return the transaction set
460497 return & TransactionsByPriceAndNonce {
461- txs : txs ,
462- heads : heads ,
463- signer : signer ,
498+ txs : txs ,
499+ heads : heads ,
500+ signer : signer ,
501+ baseFee : baseFee ,
464502 }
465503}
466504
@@ -469,18 +507,20 @@ func (t *TransactionsByPriceAndNonce) Peek() *Transaction {
469507 if len (t .heads ) == 0 {
470508 return nil
471509 }
472- return t .heads [0 ]
510+ return t .heads [0 ]. tx
473511}
474512
475513// Shift replaces the current best head with the next one from the same account.
476514func (t * TransactionsByPriceAndNonce ) Shift () {
477- acc , _ := Sender (t .signer , t .heads [0 ])
515+ acc , _ := Sender (t .signer , t .heads [0 ]. tx )
478516 if txs , ok := t .txs [acc ]; ok && len (txs ) > 0 {
479- t .heads [0 ], t .txs [acc ] = txs [0 ], txs [1 :]
480- heap .Fix (& t .heads , 0 )
481- } else {
482- heap .Pop (& t .heads )
517+ if wrapped , err := NewTxWithMinerFee (txs [0 ], t .baseFee ); err == nil {
518+ t .heads [0 ], t .txs [acc ] = wrapped , txs [1 :]
519+ heap .Fix (& t .heads , 0 )
520+ return
521+ }
483522 }
523+ heap .Pop (& t .heads )
484524}
485525
486526// Pop removes the best transaction, *not* replacing it with the next one from
0 commit comments