@@ -18,7 +18,6 @@ package txpool
1818
1919import (
2020 "errors"
21- "fmt"
2221 "math"
2322 "math/big"
2423 "sort"
9190 // ErrFutureReplacePending is returned if a future transaction replaces a pending
9291 // transaction. Future transactions should only be able to replace other future transactions.
9392 ErrFutureReplacePending = errors .New ("future transaction tries to replace pending" )
94-
95- // ErrOverdraft is returned if a transaction would cause the senders balance to go negative
96- // thus invalidating a potential large number of transactions.
97- ErrOverdraft = errors .New ("transaction would cause overdraft" )
9893)
9994
10095var (
@@ -178,8 +173,7 @@ type Config struct {
178173 Lifetime time.Duration // Maximum amount of time non-executable transaction are queued
179174}
180175
181- // DefaultConfig contains the default configurations for the transaction
182- // pool.
176+ // DefaultConfig contains the default configurations for the transaction pool.
183177var DefaultConfig = Config {
184178 Journal : "transactions.rlp" ,
185179 Rejournal : time .Hour ,
@@ -245,20 +239,15 @@ type TxPool struct {
245239 config Config
246240 chainconfig * params.ChainConfig
247241 chain blockChain
248- gasPrice * big.Int
242+ gasTip atomic. Pointer [ big.Int ]
249243 txFeed event.Feed
250244 scope event.SubscriptionScope
251245 signer types.Signer
252246 mu sync.RWMutex
253247
254- istanbul atomic.Bool // Fork indicator whether we are in the istanbul stage.
255- eip2718 atomic.Bool // Fork indicator whether we are using EIP-2718 type transactions.
256- eip1559 atomic.Bool // Fork indicator whether we are using EIP-1559 type transactions.
257- shanghai atomic.Bool // Fork indicator whether we are in the Shanghai stage.
258-
259- currentState * state.StateDB // Current state in the blockchain head
260- pendingNonces * noncer // Pending state tracking virtual nonces
261- currentMaxGas atomic.Uint64 // Current gas limit for transaction caps
248+ currentHead atomic.Pointer [types.Header ] // Current head of the blockchain
249+ currentState * state.StateDB // Current state in the blockchain head
250+ pendingNonces * noncer // Pending state tracking virtual nonces
262251
263252 locals * accountSet // Set of local transaction to exempt from eviction rules
264253 journal * journal // Journal of local transaction to back up to disk
@@ -286,9 +275,9 @@ type txpoolResetRequest struct {
286275 oldHead , newHead * types.Header
287276}
288277
289- // NewTxPool creates a new transaction pool to gather, sort and filter inbound
278+ // New creates a new transaction pool to gather, sort and filter inbound
290279// transactions from the network.
291- func NewTxPool (config Config , chainconfig * params.ChainConfig , chain blockChain ) * TxPool {
280+ func New (config Config , chainconfig * params.ChainConfig , chain blockChain ) * TxPool {
292281 // Sanitize the input to ensure no vulnerable gas prices are set
293282 config = (& config ).sanitize ()
294283
@@ -309,8 +298,8 @@ func NewTxPool(config Config, chainconfig *params.ChainConfig, chain blockChain)
309298 reorgDoneCh : make (chan chan struct {}),
310299 reorgShutdownCh : make (chan struct {}),
311300 initDoneCh : make (chan struct {}),
312- gasPrice : new (big.Int ).SetUint64 (config .PriceLimit ),
313301 }
302+ pool .gasTip .Store (new (big.Int ).SetUint64 (config .PriceLimit ))
314303 pool .locals = newAccountSet (pool .signer )
315304 for _ , addr := range config .Locals {
316305 log .Info ("Setting new local account" , "address" , addr )
@@ -443,33 +432,25 @@ func (pool *TxPool) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subsc
443432 return pool .scope .Track (pool .txFeed .Subscribe (ch ))
444433}
445434
446- // GasPrice returns the current gas price enforced by the transaction pool.
447- func (pool * TxPool ) GasPrice () * big.Int {
448- pool .mu .RLock ()
449- defer pool .mu .RUnlock ()
450-
451- return new (big.Int ).Set (pool .gasPrice )
452- }
453-
454- // SetGasPrice updates the minimum price required by the transaction pool for a
435+ // SetGasTip updates the minimum gas tip required by the transaction pool for a
455436// new transaction, and drops all transactions below this threshold.
456- func (pool * TxPool ) SetGasPrice ( price * big.Int ) {
437+ func (pool * TxPool ) SetGasTip ( tip * big.Int ) {
457438 pool .mu .Lock ()
458439 defer pool .mu .Unlock ()
459440
460- old := pool .gasPrice
461- pool .gasPrice = price
462- // if the min miner fee increased, remove transactions below the new threshold
463- if price .Cmp (old ) > 0 {
441+ old := pool .gasTip .Load ()
442+ pool .gasTip .Store (new (big.Int ).Set (tip ))
443+
444+ // If the min miner fee increased, remove transactions below the new threshold
445+ if tip .Cmp (old ) > 0 {
464446 // pool.priced is sorted by GasFeeCap, so we have to iterate through pool.all instead
465- drop := pool .all .RemotesBelowTip (price )
447+ drop := pool .all .RemotesBelowTip (tip )
466448 for _ , tx := range drop {
467449 pool .removeTx (tx .Hash (), false )
468450 }
469451 pool .priced .Removed (len (drop ))
470452 }
471-
472- log .Info ("Transaction pool price threshold updated" , "price" , price )
453+ log .Info ("Transaction pool tip threshold updated" , "tip" , tip )
473454}
474455
475456// Nonce returns the next nonce of an account, with all transactions executable
@@ -556,7 +537,7 @@ func (pool *TxPool) Pending(enforceTips bool) map[common.Address]types.Transacti
556537 // If the miner requests tip enforcement, cap the lists now
557538 if enforceTips && ! pool .locals .contains (addr ) {
558539 for i , tx := range txs {
559- if tx .EffectiveGasTipIntCmp (pool .gasPrice , pool .priced .urgent .baseFee ) < 0 {
540+ if tx .EffectiveGasTipIntCmp (pool .gasTip . Load () , pool .priced .urgent .baseFee ) < 0 {
560541 txs = txs [:i ]
561542 break
562543 }
@@ -598,93 +579,48 @@ func (pool *TxPool) local() map[common.Address]types.Transactions {
598579// This check is meant as an early check which only needs to be performed once,
599580// and does not require the pool mutex to be held.
600581func (pool * TxPool ) validateTxBasics (tx * types.Transaction , local bool ) error {
601- // Accept only legacy transactions until EIP-2718/2930 activates.
602- if ! pool .eip2718 .Load () && tx .Type () != types .LegacyTxType {
603- return core .ErrTxTypeNotSupported
604- }
605- // Reject dynamic fee transactions until EIP-1559 activates.
606- if ! pool .eip1559 .Load () && tx .Type () == types .DynamicFeeTxType {
607- return core .ErrTxTypeNotSupported
608- }
609- // Reject blob transactions forever, those will have their own pool.
610- if tx .Type () == types .BlobTxType {
611- return core .ErrTxTypeNotSupported
612- }
613- // Reject transactions over defined size to prevent DOS attacks
614- if tx .Size () > txMaxSize {
615- return ErrOversizedData
616- }
617- // Check whether the init code size has been exceeded.
618- if pool .shanghai .Load () && tx .To () == nil && len (tx .Data ()) > params .MaxInitCodeSize {
619- return fmt .Errorf ("%w: code size %v limit %v" , core .ErrMaxInitCodeSizeExceeded , len (tx .Data ()), params .MaxInitCodeSize )
620- }
621- // Transactions can't be negative. This may never happen using RLP decoded
622- // transactions but may occur if you create a transaction using the RPC.
623- if tx .Value ().Sign () < 0 {
624- return ErrNegativeValue
625- }
626- // Ensure the transaction doesn't exceed the current block limit gas.
627- if pool .currentMaxGas .Load () < tx .Gas () {
628- return ErrGasLimit
629- }
630- // Sanity check for extremely large numbers
631- if tx .GasFeeCap ().BitLen () > 256 {
632- return core .ErrFeeCapVeryHigh
633- }
634- if tx .GasTipCap ().BitLen () > 256 {
635- return core .ErrTipVeryHigh
582+ opts := & ValidationOptions {
583+ Config : pool .chainconfig ,
584+ Accept : 0 |
585+ 1 << types .LegacyTxType |
586+ 1 << types .AccessListTxType |
587+ 1 << types .DynamicFeeTxType ,
588+ MaxSize : txMaxSize ,
589+ MinTip : pool .gasTip .Load (),
636590 }
637- // Ensure gasFeeCap is greater than or equal to gasTipCap.
638- if tx .GasFeeCapIntCmp (tx .GasTipCap ()) < 0 {
639- return core .ErrTipAboveFeeCap
640- }
641- // Make sure the transaction is signed properly.
642- if _ , err := types .Sender (pool .signer , tx ); err != nil {
643- return ErrInvalidSender
644- }
645- // Drop non-local transactions under our own minimal accepted gas price or tip
646- if ! local && tx .GasTipCapIntCmp (pool .gasPrice ) < 0 {
647- return ErrUnderpriced
591+ if local {
592+ opts .MinTip = new (big.Int )
648593 }
649- // Ensure the transaction has more gas than the basic tx fee.
650- intrGas , err := core .IntrinsicGas (tx .Data (), tx .AccessList (), tx .To () == nil , true , pool .istanbul .Load (), pool .shanghai .Load ())
651- if err != nil {
594+ if err := ValidateTransaction (tx , nil , nil , nil , pool .currentHead .Load (), pool .signer , opts ); err != nil {
652595 return err
653596 }
654- if tx .Gas () < intrGas {
655- return core .ErrIntrinsicGas
656- }
657597 return nil
658598}
659599
660600// validateTx checks whether a transaction is valid according to the consensus
661601// rules and adheres to some heuristic limits of the local node (price and size).
662602func (pool * TxPool ) validateTx (tx * types.Transaction , local bool ) error {
663- // Signature has been checked already, this cannot error.
664- from , _ := types .Sender (pool .signer , tx )
665- // Ensure the transaction adheres to nonce ordering
666- if pool .currentState .GetNonce (from ) > tx .Nonce () {
667- return core .ErrNonceTooLow
668- }
669- // Transactor should have enough funds to cover the costs
670- // cost == V + GP * GL
671- balance := pool .currentState .GetBalance (from )
672- if balance .Cmp (tx .Cost ()) < 0 {
673- return core .ErrInsufficientFunds
674- }
675-
676- // Verify that replacing transactions will not result in overdraft
677- list := pool .pending [from ]
678- if list != nil { // Sender already has pending txs
679- sum := new (big.Int ).Add (tx .Cost (), list .totalcost )
680- if repl := list .txs .Get (tx .Nonce ()); repl != nil {
681- // Deduct the cost of a transaction replaced by this
682- sum .Sub (sum , repl .Cost ())
683- }
684- if balance .Cmp (sum ) < 0 {
685- log .Trace ("Replacing transactions would overdraft" , "sender" , from , "balance" , pool .currentState .GetBalance (from ), "required" , sum )
686- return ErrOverdraft
687- }
603+ opts := & ValidationOptionsWithState {
604+ State : pool .currentState ,
605+
606+ FirstNonceGap : nil , // Pool allows arbitrary arrival order, don't invalidate nonce gaps
607+ ExistingExpenditure : func (addr common.Address ) * big.Int {
608+ if list := pool .pending [addr ]; list != nil {
609+ return list .totalcost
610+ }
611+ return new (big.Int )
612+ },
613+ ExistingCost : func (addr common.Address , nonce uint64 ) * big.Int {
614+ if list := pool .pending [addr ]; list != nil {
615+ if tx := list .txs .Get (nonce ); tx != nil {
616+ return tx .Cost ()
617+ }
618+ }
619+ return nil
620+ },
621+ }
622+ if err := ValidateTransactionWithState (tx , pool .signer , opts ); err != nil {
623+ return err
688624 }
689625 return nil
690626}
@@ -995,7 +931,6 @@ func (pool *TxPool) addTxs(txs []*types.Transaction, local, sync bool) []error {
995931 // Exclude transactions with basic errors, e.g invalid signatures and
996932 // insufficient intrinsic gas as soon as possible and cache senders
997933 // in transactions before obtaining lock
998-
999934 if err := pool .validateTxBasics (tx , local ); err != nil {
1000935 errs [i ] = err
1001936 invalidTxMeter .Mark (1 )
@@ -1385,21 +1320,14 @@ func (pool *TxPool) reset(oldHead, newHead *types.Header) {
13851320 log .Error ("Failed to reset txpool state" , "err" , err )
13861321 return
13871322 }
1323+ pool .currentHead .Store (newHead )
13881324 pool .currentState = statedb
13891325 pool .pendingNonces = newNoncer (statedb )
1390- pool .currentMaxGas .Store (newHead .GasLimit )
13911326
13921327 // Inject any transactions discarded due to reorgs
13931328 log .Debug ("Reinjecting stale transactions" , "count" , len (reinject ))
13941329 core .SenderCacher .Recover (pool .signer , reinject )
13951330 pool .addTxsLocked (reinject , false )
1396-
1397- // Update all fork indicator by next pending block number.
1398- next := new (big.Int ).Add (newHead .Number , big .NewInt (1 ))
1399- pool .istanbul .Store (pool .chainconfig .IsIstanbul (next ))
1400- pool .eip2718 .Store (pool .chainconfig .IsBerlin (next ))
1401- pool .eip1559 .Store (pool .chainconfig .IsLondon (next ))
1402- pool .shanghai .Store (pool .chainconfig .IsShanghai (next , uint64 (time .Now ().Unix ())))
14031331}
14041332
14051333// promoteExecutables moves transactions that have become processable from the
@@ -1410,6 +1338,7 @@ func (pool *TxPool) promoteExecutables(accounts []common.Address) []*types.Trans
14101338 var promoted []* types.Transaction
14111339
14121340 // Iterate over all accounts and promote any executable transactions
1341+ gasLimit := pool .currentHead .Load ().GasLimit
14131342 for _ , addr := range accounts {
14141343 list := pool .queue [addr ]
14151344 if list == nil {
@@ -1423,7 +1352,7 @@ func (pool *TxPool) promoteExecutables(accounts []common.Address) []*types.Trans
14231352 }
14241353 log .Trace ("Removed old queued transactions" , "count" , len (forwards ))
14251354 // Drop all transactions that are too costly (low balance or out of gas)
1426- drops , _ := list .Filter (pool .currentState .GetBalance (addr ), pool . currentMaxGas . Load () )
1355+ drops , _ := list .Filter (pool .currentState .GetBalance (addr ), gasLimit )
14271356 for _ , tx := range drops {
14281357 hash := tx .Hash ()
14291358 pool .all .Remove (hash )
@@ -1609,6 +1538,7 @@ func (pool *TxPool) truncateQueue() {
16091538// to trigger a re-heap is this function
16101539func (pool * TxPool ) demoteUnexecutables () {
16111540 // Iterate over all accounts and demote any non-executable transactions
1541+ gasLimit := pool .currentHead .Load ().GasLimit
16121542 for addr , list := range pool .pending {
16131543 nonce := pool .currentState .GetNonce (addr )
16141544
@@ -1620,7 +1550,7 @@ func (pool *TxPool) demoteUnexecutables() {
16201550 log .Trace ("Removed old pending transaction" , "hash" , hash )
16211551 }
16221552 // Drop all transactions that are too costly (low balance or out of gas), and queue any invalids back for later
1623- drops , invalids := list .Filter (pool .currentState .GetBalance (addr ), pool . currentMaxGas . Load () )
1553+ drops , invalids := list .Filter (pool .currentState .GetBalance (addr ), gasLimit )
16241554 for _ , tx := range drops {
16251555 hash := tx .Hash ()
16261556 log .Trace ("Removed unpayable pending transaction" , "hash" , hash )
0 commit comments