@@ -35,16 +35,41 @@ import (
35
35
)
36
36
37
37
var (
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.
42
51
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" )
48
73
)
49
74
50
75
var (
@@ -54,16 +79,16 @@ var (
54
79
55
80
var (
56
81
// 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
61
86
62
87
// 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
67
92
68
93
// General tx metrics
69
94
invalidTxCounter = metrics .NewCounter ("txpool/invalid" )
@@ -301,19 +326,6 @@ func (pool *TxPool) Stats() (int, int) {
301
326
return pool .stats ()
302
327
}
303
328
304
- // validateInternals checks if the content in pool.all
305
- // is consistent with the numbers reported in pending and queued
306
- func (pool * TxPool ) validateInternals () error {
307
- pool .mu .RLock ()
308
- defer pool .mu .RUnlock ()
309
- p , q := pool .stats ()
310
- a := len (pool .all )
311
- if a != p + q {
312
- return fmt .Errorf ("Pool.all size %d != %d pending + %d queued" , a , p , q )
313
- }
314
- return nil
315
- }
316
-
317
329
// stats retrieves the current pool stats, namely the number of pending and the
318
330
// number of queued (non-executable) transactions.
319
331
func (pool * TxPool ) stats () (int , int ) {
@@ -387,7 +399,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error {
387
399
}
388
400
// Last but not least check for nonce errors
389
401
if currentState .GetNonce (from ) > tx .Nonce () {
390
- return ErrNonce
402
+ return ErrNonceTooLow
391
403
}
392
404
393
405
// Check the transaction doesn't exceed the current
@@ -408,12 +420,15 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error {
408
420
if currentState .GetBalance (from ).Cmp (tx .Cost ()) < 0 {
409
421
return ErrInsufficientFunds
410
422
}
411
-
412
423
intrGas := IntrinsicGas (tx .Data (), tx .To () == nil , pool .homestead )
413
424
if tx .Gas ().Cmp (intrGas ) < 0 {
414
425
return ErrIntrinsicGas
415
426
}
416
427
428
+ // Heuristic limit, reject transactions over 32KB to prevent DOS attacks
429
+ if tx .Size () > 32 * 1024 {
430
+ return ErrOversizedData
431
+ }
417
432
return nil
418
433
}
419
434
@@ -651,8 +666,9 @@ func (pool *TxPool) removeTx(hash common.Hash) {
651
666
}
652
667
// Update the account nonce if needed
653
668
if nonce := tx .Nonce (); pool .pendingState .GetNonce (addr ) > nonce {
654
- pool .pendingState .SetNonce (addr , tx . Nonce () )
669
+ pool .pendingState .SetNonce (addr , nonce )
655
670
}
671
+ return
656
672
}
657
673
}
658
674
// Transaction is in the future queue
@@ -709,10 +725,10 @@ func (pool *TxPool) promoteExecutables(state *state.StateDB, accounts []common.A
709
725
// Drop all transactions over the allowed limit
710
726
for _ , tx := range list .Cap (int (pool .config .AccountQueue )) {
711
727
hash := tx .Hash ()
712
- log .Trace ("Removed cap-exceeding queued transaction" , "hash" , hash )
713
728
delete (pool .all , hash )
714
729
pool .priced .Removed ()
715
- queuedRLCounter .Inc (1 )
730
+ queuedRateLimitCounter .Inc (1 )
731
+ log .Trace ("Removed cap-exceeding queued transaction" , "hash" , hash )
716
732
}
717
733
queued += uint64 (list .Len ())
718
734
@@ -758,7 +774,18 @@ func (pool *TxPool) promoteExecutables(state *state.StateDB, accounts []common.A
758
774
for pending > pool .config .GlobalSlots && pool .pending [offenders [len (offenders )- 2 ]].Len () > threshold {
759
775
for i := 0 ; i < len (offenders )- 1 ; i ++ {
760
776
list := pool.pending [offenders [i ]]
761
- 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
+ }
762
789
pending --
763
790
}
764
791
}
@@ -769,12 +796,23 @@ func (pool *TxPool) promoteExecutables(state *state.StateDB, accounts []common.A
769
796
for pending > pool .config .GlobalSlots && uint64 (pool .pending [offenders [len (offenders )- 1 ]].Len ()) > pool .config .AccountSlots {
770
797
for _ , addr := range offenders {
771
798
list := pool .pending [addr ]
772
- 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
+ }
773
811
pending --
774
812
}
775
813
}
776
814
}
777
- pendingRLCounter .Inc (int64 (pendingBeforeCap - pending ))
815
+ pendingRateLimitCounter .Inc (int64 (pendingBeforeCap - pending ))
778
816
}
779
817
// If we've queued more transactions than the hard limit, drop oldest ones
780
818
if queued > pool .config .GlobalQueue {
@@ -798,15 +836,15 @@ func (pool *TxPool) promoteExecutables(state *state.StateDB, accounts []common.A
798
836
pool .removeTx (tx .Hash ())
799
837
}
800
838
drop -= size
801
- queuedRLCounter .Inc (int64 (size ))
839
+ queuedRateLimitCounter .Inc (int64 (size ))
802
840
continue
803
841
}
804
842
// Otherwise drop only last few transactions
805
843
txs := list .Flatten ()
806
844
for i := len (txs ) - 1 ; i >= 0 && drop > 0 ; i -- {
807
845
pool .removeTx (txs [i ].Hash ())
808
846
drop --
809
- queuedRLCounter .Inc (1 )
847
+ queuedRateLimitCounter .Inc (1 )
810
848
}
811
849
}
812
850
}
0 commit comments