@@ -35,16 +35,41 @@ import (
3535)
3636
3737var (
38- // Transaction Pool Errors
39- ErrInvalidSender = errors .New ("invalid sender" )
40- ErrNonce = errors .New ("nonce too low" )
41- ErrUnderpriced = errors .New ("transaction underpriced" )
38+ // ErrInvalidSender is returned if the transaction contains an invalid signature.
39+ ErrInvalidSender = errors .New ("invalid sender" )
40+
41+ // ErrNonceTooLow is returned if the nonce of a transaction is lower than the
42+ // one present in the local chain.
43+ ErrNonceTooLow = errors .New ("nonce too low" )
44+
45+ // ErrUnderpriced is returned if a transaction's gas price is below the minimum
46+ // configured for the transaction pool.
47+ ErrUnderpriced = errors .New ("transaction underpriced" )
48+
49+ // ErrReplaceUnderpriced is returned if a transaction is attempted to be replaced
50+ // with a different one without the required price bump.
4251 ErrReplaceUnderpriced = errors .New ("replacement transaction underpriced" )
43- ErrBalance = errors .New ("insufficient balance" )
44- ErrInsufficientFunds = errors .New ("insufficient funds for gas * price + value" )
45- ErrIntrinsicGas = errors .New ("intrinsic gas too low" )
46- ErrGasLimit = errors .New ("exceeds block gas limit" )
47- ErrNegativeValue = errors .New ("negative value" )
52+
53+ // ErrInsufficientFunds is returned if the total cost of executing a transaction
54+ // is higher than the balance of the user's account.
55+ ErrInsufficientFunds = errors .New ("insufficient funds for gas * price + value" )
56+
57+ // ErrIntrinsicGas is returned if the transaction is specified to use less gas
58+ // than required to start the invocation.
59+ ErrIntrinsicGas = errors .New ("intrinsic gas too low" )
60+
61+ // ErrGasLimit is returned if a transaction's requested gas limit exceeds the
62+ // maximum allowance of the current block.
63+ ErrGasLimit = errors .New ("exceeds block gas limit" )
64+
65+ // ErrNegativeValue is a sanity error to ensure noone is able to specify a
66+ // transaction with a negative value.
67+ ErrNegativeValue = errors .New ("negative value" )
68+
69+ // ErrOversizedData is returned if the input data of a transaction is greater
70+ // than some meaningful limit a user might use. This is not a consensus error
71+ // making the transaction invalid, rather a DOS protection.
72+ ErrOversizedData = errors .New ("oversized data" )
4873)
4974
5075var (
@@ -54,16 +79,16 @@ var (
5479
5580var (
5681 // Metrics for the pending pool
57- pendingDiscardCounter = metrics .NewCounter ("txpool/pending/discard" )
58- pendingReplaceCounter = metrics .NewCounter ("txpool/pending/replace" )
59- pendingRLCounter = metrics .NewCounter ("txpool/pending/ratelimit" ) // Dropped due to rate limiting
60- pendingNofundsCounter = metrics .NewCounter ("txpool/pending/nofunds" ) // Dropped due to out-of-funds
82+ pendingDiscardCounter = metrics .NewCounter ("txpool/pending/discard" )
83+ pendingReplaceCounter = metrics .NewCounter ("txpool/pending/replace" )
84+ pendingRateLimitCounter = metrics .NewCounter ("txpool/pending/ratelimit" ) // Dropped due to rate limiting
85+ pendingNofundsCounter = metrics .NewCounter ("txpool/pending/nofunds" ) // Dropped due to out-of-funds
6186
6287 // Metrics for the queued pool
63- queuedDiscardCounter = metrics .NewCounter ("txpool/queued/discard" )
64- queuedReplaceCounter = metrics .NewCounter ("txpool/queued/replace" )
65- queuedRLCounter = metrics .NewCounter ("txpool/queued/ratelimit" ) // Dropped due to rate limiting
66- queuedNofundsCounter = metrics .NewCounter ("txpool/queued/nofunds" ) // Dropped due to out-of-funds
88+ queuedDiscardCounter = metrics .NewCounter ("txpool/queued/discard" )
89+ queuedReplaceCounter = metrics .NewCounter ("txpool/queued/replace" )
90+ queuedRateLimitCounter = metrics .NewCounter ("txpool/queued/ratelimit" ) // Dropped due to rate limiting
91+ queuedNofundsCounter = metrics .NewCounter ("txpool/queued/nofunds" ) // Dropped due to out-of-funds
6792
6893 // General tx metrics
6994 invalidTxCounter = metrics .NewCounter ("txpool/invalid" )
@@ -374,7 +399,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error {
374399 }
375400 // Last but not least check for nonce errors
376401 if currentState .GetNonce (from ) > tx .Nonce () {
377- return ErrNonce
402+ return ErrNonceTooLow
378403 }
379404
380405 // Check the transaction doesn't exceed the current
@@ -395,12 +420,15 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error {
395420 if currentState .GetBalance (from ).Cmp (tx .Cost ()) < 0 {
396421 return ErrInsufficientFunds
397422 }
398-
399423 intrGas := IntrinsicGas (tx .Data (), tx .To () == nil , pool .homestead )
400424 if tx .Gas ().Cmp (intrGas ) < 0 {
401425 return ErrIntrinsicGas
402426 }
403427
428+ // Heuristic limit, reject transactions over 32KB to prevent DOS attacks
429+ if tx .Size () > 32 * 1024 {
430+ return ErrOversizedData
431+ }
404432 return nil
405433}
406434
@@ -638,8 +666,9 @@ func (pool *TxPool) removeTx(hash common.Hash) {
638666 }
639667 // Update the account nonce if needed
640668 if nonce := tx .Nonce (); pool .pendingState .GetNonce (addr ) > nonce {
641- pool .pendingState .SetNonce (addr , tx . Nonce () )
669+ pool .pendingState .SetNonce (addr , nonce )
642670 }
671+ return
643672 }
644673 }
645674 // Transaction is in the future queue
@@ -696,10 +725,10 @@ func (pool *TxPool) promoteExecutables(state *state.StateDB, accounts []common.A
696725 // Drop all transactions over the allowed limit
697726 for _ , tx := range list .Cap (int (pool .config .AccountQueue )) {
698727 hash := tx .Hash ()
699- log .Trace ("Removed cap-exceeding queued transaction" , "hash" , hash )
700728 delete (pool .all , hash )
701729 pool .priced .Removed ()
702- queuedRLCounter .Inc (1 )
730+ queuedRateLimitCounter .Inc (1 )
731+ log .Trace ("Removed cap-exceeding queued transaction" , "hash" , hash )
703732 }
704733 queued += uint64 (list .Len ())
705734
@@ -745,7 +774,18 @@ func (pool *TxPool) promoteExecutables(state *state.StateDB, accounts []common.A
745774 for pending > pool .config .GlobalSlots && pool .pending [offenders [len (offenders )- 2 ]].Len () > threshold {
746775 for i := 0 ; i < len (offenders )- 1 ; i ++ {
747776 list := pool.pending [offenders [i ]]
748- list .Cap (list .Len () - 1 )
777+ for _ , tx := range list .Cap (list .Len () - 1 ) {
778+ // Drop the transaction from the global pools too
779+ hash := tx .Hash ()
780+ delete (pool .all , hash )
781+ pool .priced .Removed ()
782+
783+ // Update the account nonce to the dropped transaction
784+ if nonce := tx .Nonce (); pool .pendingState .GetNonce (offenders [i ]) > nonce {
785+ pool .pendingState .SetNonce (offenders [i ], nonce )
786+ }
787+ log .Trace ("Removed fairness-exceeding pending transaction" , "hash" , hash )
788+ }
749789 pending --
750790 }
751791 }
@@ -756,12 +796,23 @@ func (pool *TxPool) promoteExecutables(state *state.StateDB, accounts []common.A
756796 for pending > pool .config .GlobalSlots && uint64 (pool .pending [offenders [len (offenders )- 1 ]].Len ()) > pool .config .AccountSlots {
757797 for _ , addr := range offenders {
758798 list := pool .pending [addr ]
759- list .Cap (list .Len () - 1 )
799+ for _ , tx := range list .Cap (list .Len () - 1 ) {
800+ // Drop the transaction from the global pools too
801+ hash := tx .Hash ()
802+ delete (pool .all , hash )
803+ pool .priced .Removed ()
804+
805+ // Update the account nonce to the dropped transaction
806+ if nonce := tx .Nonce (); pool .pendingState .GetNonce (addr ) > nonce {
807+ pool .pendingState .SetNonce (addr , nonce )
808+ }
809+ log .Trace ("Removed fairness-exceeding pending transaction" , "hash" , hash )
810+ }
760811 pending --
761812 }
762813 }
763814 }
764- pendingRLCounter .Inc (int64 (pendingBeforeCap - pending ))
815+ pendingRateLimitCounter .Inc (int64 (pendingBeforeCap - pending ))
765816 }
766817 // If we've queued more transactions than the hard limit, drop oldest ones
767818 if queued > pool .config .GlobalQueue {
@@ -785,15 +836,15 @@ func (pool *TxPool) promoteExecutables(state *state.StateDB, accounts []common.A
785836 pool .removeTx (tx .Hash ())
786837 }
787838 drop -= size
788- queuedRLCounter .Inc (int64 (size ))
839+ queuedRateLimitCounter .Inc (int64 (size ))
789840 continue
790841 }
791842 // Otherwise drop only last few transactions
792843 txs := list .Flatten ()
793844 for i := len (txs ) - 1 ; i >= 0 && drop > 0 ; i -- {
794845 pool .removeTx (txs [i ].Hash ())
795846 drop --
796- queuedRLCounter .Inc (1 )
847+ queuedRateLimitCounter .Inc (1 )
797848 }
798849 }
799850 }
0 commit comments