@@ -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" )
@@ -374,7 +399,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error {
374
399
}
375
400
// Last but not least check for nonce errors
376
401
if currentState .GetNonce (from ) > tx .Nonce () {
377
- return ErrNonce
402
+ return ErrNonceTooLow
378
403
}
379
404
380
405
// Check the transaction doesn't exceed the current
@@ -395,12 +420,15 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error {
395
420
if currentState .GetBalance (from ).Cmp (tx .Cost ()) < 0 {
396
421
return ErrInsufficientFunds
397
422
}
398
-
399
423
intrGas := IntrinsicGas (tx .Data (), tx .To () == nil , pool .homestead )
400
424
if tx .Gas ().Cmp (intrGas ) < 0 {
401
425
return ErrIntrinsicGas
402
426
}
403
427
428
+ // Heuristic limit, reject transactions over 32KB to prevent DOS attacks
429
+ if tx .Size () > 32 * 1024 {
430
+ return ErrOversizedData
431
+ }
404
432
return nil
405
433
}
406
434
@@ -638,8 +666,9 @@ func (pool *TxPool) removeTx(hash common.Hash) {
638
666
}
639
667
// Update the account nonce if needed
640
668
if nonce := tx .Nonce (); pool .pendingState .GetNonce (addr ) > nonce {
641
- pool .pendingState .SetNonce (addr , tx . Nonce () )
669
+ pool .pendingState .SetNonce (addr , nonce )
642
670
}
671
+ return
643
672
}
644
673
}
645
674
// Transaction is in the future queue
@@ -696,10 +725,10 @@ func (pool *TxPool) promoteExecutables(state *state.StateDB, accounts []common.A
696
725
// Drop all transactions over the allowed limit
697
726
for _ , tx := range list .Cap (int (pool .config .AccountQueue )) {
698
727
hash := tx .Hash ()
699
- log .Trace ("Removed cap-exceeding queued transaction" , "hash" , hash )
700
728
delete (pool .all , hash )
701
729
pool .priced .Removed ()
702
- queuedRLCounter .Inc (1 )
730
+ queuedRateLimitCounter .Inc (1 )
731
+ log .Trace ("Removed cap-exceeding queued transaction" , "hash" , hash )
703
732
}
704
733
queued += uint64 (list .Len ())
705
734
@@ -745,7 +774,18 @@ func (pool *TxPool) promoteExecutables(state *state.StateDB, accounts []common.A
745
774
for pending > pool .config .GlobalSlots && pool .pending [offenders [len (offenders )- 2 ]].Len () > threshold {
746
775
for i := 0 ; i < len (offenders )- 1 ; i ++ {
747
776
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
+ }
749
789
pending --
750
790
}
751
791
}
@@ -756,12 +796,23 @@ func (pool *TxPool) promoteExecutables(state *state.StateDB, accounts []common.A
756
796
for pending > pool .config .GlobalSlots && uint64 (pool .pending [offenders [len (offenders )- 1 ]].Len ()) > pool .config .AccountSlots {
757
797
for _ , addr := range offenders {
758
798
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
+ }
760
811
pending --
761
812
}
762
813
}
763
814
}
764
- pendingRLCounter .Inc (int64 (pendingBeforeCap - pending ))
815
+ pendingRateLimitCounter .Inc (int64 (pendingBeforeCap - pending ))
765
816
}
766
817
// If we've queued more transactions than the hard limit, drop oldest ones
767
818
if queued > pool .config .GlobalQueue {
@@ -785,15 +836,15 @@ func (pool *TxPool) promoteExecutables(state *state.StateDB, accounts []common.A
785
836
pool .removeTx (tx .Hash ())
786
837
}
787
838
drop -= size
788
- queuedRLCounter .Inc (int64 (size ))
839
+ queuedRateLimitCounter .Inc (int64 (size ))
789
840
continue
790
841
}
791
842
// Otherwise drop only last few transactions
792
843
txs := list .Flatten ()
793
844
for i := len (txs ) - 1 ; i >= 0 && drop > 0 ; i -- {
794
845
pool .removeTx (txs [i ].Hash ())
795
846
drop --
796
- queuedRLCounter .Inc (1 )
847
+ queuedRateLimitCounter .Inc (1 )
797
848
}
798
849
}
799
850
}
0 commit comments