Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
G
Geth-Modification
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
张蕾
Geth-Modification
Commits
eebde1a2
Unverified
Commit
eebde1a2
authored
Jun 22, 2017
by
Péter Szilágyi
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
core: ensure transactions correctly drop on pool limiting
parent
b0b3cf2e
Changes
3
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
167 additions
and
88 deletions
+167
-88
tx_pool.go
core/tx_pool.go
+78
-40
tx_pool_test.go
core/tx_pool_test.go
+88
-47
txpool.go
light/txpool.go
+1
-1
No files found.
core/tx_pool.go
View file @
eebde1a2
...
...
@@ -35,16 +35,41 @@ import (
)
var
(
// Transaction Pool Errors
ErrInvalidSender
=
errors
.
New
(
"invalid sender"
)
ErrNonce
=
errors
.
New
(
"nonce too low"
)
ErrUnderpriced
=
errors
.
New
(
"transaction underpriced"
)
// ErrInvalidSender is returned if the transaction contains an invalid signature.
ErrInvalidSender
=
errors
.
New
(
"invalid sender"
)
// ErrNonceTooLow is returned if the nonce of a transaction is lower than the
// one present in the local chain.
ErrNonceTooLow
=
errors
.
New
(
"nonce too low"
)
// ErrUnderpriced is returned if a transaction's gas price is below the minimum
// configured for the transaction pool.
ErrUnderpriced
=
errors
.
New
(
"transaction underpriced"
)
// ErrReplaceUnderpriced is returned if a transaction is attempted to be replaced
// with a different one without the required price bump.
ErrReplaceUnderpriced
=
errors
.
New
(
"replacement transaction underpriced"
)
ErrBalance
=
errors
.
New
(
"insufficient balance"
)
ErrInsufficientFunds
=
errors
.
New
(
"insufficient funds for gas * price + value"
)
ErrIntrinsicGas
=
errors
.
New
(
"intrinsic gas too low"
)
ErrGasLimit
=
errors
.
New
(
"exceeds block gas limit"
)
ErrNegativeValue
=
errors
.
New
(
"negative value"
)
// ErrInsufficientFunds is returned if the total cost of executing a transaction
// is higher than the balance of the user's account.
ErrInsufficientFunds
=
errors
.
New
(
"insufficient funds for gas * price + value"
)
// ErrIntrinsicGas is returned if the transaction is specified to use less gas
// than required to start the invocation.
ErrIntrinsicGas
=
errors
.
New
(
"intrinsic gas too low"
)
// ErrGasLimit is returned if a transaction's requested gas limit exceeds the
// maximum allowance of the current block.
ErrGasLimit
=
errors
.
New
(
"exceeds block gas limit"
)
// ErrNegativeValue is a sanity error to ensure noone is able to specify a
// transaction with a negative value.
ErrNegativeValue
=
errors
.
New
(
"negative value"
)
// ErrOversizedData is returned if the input data of a transaction is greater
// than some meaningful limit a user might use. This is not a consensus error
// making the transaction invalid, rather a DOS protection.
ErrOversizedData
=
errors
.
New
(
"oversized data"
)
)
var
(
...
...
@@ -54,16 +79,16 @@ var (
var
(
// Metrics for the pending pool
pendingDiscardCounter
=
metrics
.
NewCounter
(
"txpool/pending/discard"
)
pendingReplaceCounter
=
metrics
.
NewCounter
(
"txpool/pending/replace"
)
pendingR
LCounter
=
metrics
.
NewCounter
(
"txpool/pending/ratelimit"
)
// Dropped due to rate limiting
pendingNofundsCounter
=
metrics
.
NewCounter
(
"txpool/pending/nofunds"
)
// Dropped due to out-of-funds
pendingDiscardCounter
=
metrics
.
NewCounter
(
"txpool/pending/discard"
)
pendingReplaceCounter
=
metrics
.
NewCounter
(
"txpool/pending/replace"
)
pendingR
ateLimitCounter
=
metrics
.
NewCounter
(
"txpool/pending/ratelimit"
)
// Dropped due to rate limiting
pendingNofundsCounter
=
metrics
.
NewCounter
(
"txpool/pending/nofunds"
)
// Dropped due to out-of-funds
// Metrics for the queued pool
queuedDiscardCounter
=
metrics
.
NewCounter
(
"txpool/queued/discard"
)
queuedReplaceCounter
=
metrics
.
NewCounter
(
"txpool/queued/replace"
)
queuedR
LCounter
=
metrics
.
NewCounter
(
"txpool/queued/ratelimit"
)
// Dropped due to rate limiting
queuedNofundsCounter
=
metrics
.
NewCounter
(
"txpool/queued/nofunds"
)
// Dropped due to out-of-funds
queuedDiscardCounter
=
metrics
.
NewCounter
(
"txpool/queued/discard"
)
queuedReplaceCounter
=
metrics
.
NewCounter
(
"txpool/queued/replace"
)
queuedR
ateLimitCounter
=
metrics
.
NewCounter
(
"txpool/queued/ratelimit"
)
// Dropped due to rate limiting
queuedNofundsCounter
=
metrics
.
NewCounter
(
"txpool/queued/nofunds"
)
// Dropped due to out-of-funds
// General tx metrics
invalidTxCounter
=
metrics
.
NewCounter
(
"txpool/invalid"
)
...
...
@@ -301,19 +326,6 @@ func (pool *TxPool) Stats() (int, int) {
return
pool
.
stats
()
}
// validateInternals checks if the content in pool.all
// is consistent with the numbers reported in pending and queued
func
(
pool
*
TxPool
)
validateInternals
()
error
{
pool
.
mu
.
RLock
()
defer
pool
.
mu
.
RUnlock
()
p
,
q
:=
pool
.
stats
()
a
:=
len
(
pool
.
all
)
if
a
!=
p
+
q
{
return
fmt
.
Errorf
(
"Pool.all size %d != %d pending + %d queued"
,
a
,
p
,
q
)
}
return
nil
}
// stats retrieves the current pool stats, namely the number of pending and the
// number of queued (non-executable) transactions.
func
(
pool
*
TxPool
)
stats
()
(
int
,
int
)
{
...
...
@@ -387,7 +399,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error {
}
// Last but not least check for nonce errors
if
currentState
.
GetNonce
(
from
)
>
tx
.
Nonce
()
{
return
ErrNonce
return
ErrNonce
TooLow
}
// Check the transaction doesn't exceed the current
...
...
@@ -408,12 +420,15 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error {
if
currentState
.
GetBalance
(
from
)
.
Cmp
(
tx
.
Cost
())
<
0
{
return
ErrInsufficientFunds
}
intrGas
:=
IntrinsicGas
(
tx
.
Data
(),
tx
.
To
()
==
nil
,
pool
.
homestead
)
if
tx
.
Gas
()
.
Cmp
(
intrGas
)
<
0
{
return
ErrIntrinsicGas
}
// Heuristic limit, reject transactions over 32KB to prevent DOS attacks
if
tx
.
Size
()
>
32
*
1024
{
return
ErrOversizedData
}
return
nil
}
...
...
@@ -651,8 +666,9 @@ func (pool *TxPool) removeTx(hash common.Hash) {
}
// Update the account nonce if needed
if
nonce
:=
tx
.
Nonce
();
pool
.
pendingState
.
GetNonce
(
addr
)
>
nonce
{
pool
.
pendingState
.
SetNonce
(
addr
,
tx
.
Nonce
()
)
pool
.
pendingState
.
SetNonce
(
addr
,
nonce
)
}
return
}
}
// Transaction is in the future queue
...
...
@@ -709,10 +725,10 @@ func (pool *TxPool) promoteExecutables(state *state.StateDB, accounts []common.A
// Drop all transactions over the allowed limit
for
_
,
tx
:=
range
list
.
Cap
(
int
(
pool
.
config
.
AccountQueue
))
{
hash
:=
tx
.
Hash
()
log
.
Trace
(
"Removed cap-exceeding queued transaction"
,
"hash"
,
hash
)
delete
(
pool
.
all
,
hash
)
pool
.
priced
.
Removed
()
queuedRLCounter
.
Inc
(
1
)
queuedRateLimitCounter
.
Inc
(
1
)
log
.
Trace
(
"Removed cap-exceeding queued transaction"
,
"hash"
,
hash
)
}
queued
+=
uint64
(
list
.
Len
())
...
...
@@ -758,7 +774,18 @@ func (pool *TxPool) promoteExecutables(state *state.StateDB, accounts []common.A
for
pending
>
pool
.
config
.
GlobalSlots
&&
pool
.
pending
[
offenders
[
len
(
offenders
)
-
2
]]
.
Len
()
>
threshold
{
for
i
:=
0
;
i
<
len
(
offenders
)
-
1
;
i
++
{
list
:=
pool
.
pending
[
offenders
[
i
]]
list
.
Cap
(
list
.
Len
()
-
1
)
for
_
,
tx
:=
range
list
.
Cap
(
list
.
Len
()
-
1
)
{
// Drop the transaction from the global pools too
hash
:=
tx
.
Hash
()
delete
(
pool
.
all
,
hash
)
pool
.
priced
.
Removed
()
// Update the account nonce to the dropped transaction
if
nonce
:=
tx
.
Nonce
();
pool
.
pendingState
.
GetNonce
(
offenders
[
i
])
>
nonce
{
pool
.
pendingState
.
SetNonce
(
offenders
[
i
],
nonce
)
}
log
.
Trace
(
"Removed fairness-exceeding pending transaction"
,
"hash"
,
hash
)
}
pending
--
}
}
...
...
@@ -769,12 +796,23 @@ func (pool *TxPool) promoteExecutables(state *state.StateDB, accounts []common.A
for
pending
>
pool
.
config
.
GlobalSlots
&&
uint64
(
pool
.
pending
[
offenders
[
len
(
offenders
)
-
1
]]
.
Len
())
>
pool
.
config
.
AccountSlots
{
for
_
,
addr
:=
range
offenders
{
list
:=
pool
.
pending
[
addr
]
list
.
Cap
(
list
.
Len
()
-
1
)
for
_
,
tx
:=
range
list
.
Cap
(
list
.
Len
()
-
1
)
{
// Drop the transaction from the global pools too
hash
:=
tx
.
Hash
()
delete
(
pool
.
all
,
hash
)
pool
.
priced
.
Removed
()
// Update the account nonce to the dropped transaction
if
nonce
:=
tx
.
Nonce
();
pool
.
pendingState
.
GetNonce
(
addr
)
>
nonce
{
pool
.
pendingState
.
SetNonce
(
addr
,
nonce
)
}
log
.
Trace
(
"Removed fairness-exceeding pending transaction"
,
"hash"
,
hash
)
}
pending
--
}
}
}
pendingR
L
Counter
.
Inc
(
int64
(
pendingBeforeCap
-
pending
))
pendingR
ateLimit
Counter
.
Inc
(
int64
(
pendingBeforeCap
-
pending
))
}
// If we've queued more transactions than the hard limit, drop oldest ones
if
queued
>
pool
.
config
.
GlobalQueue
{
...
...
@@ -798,7 +836,7 @@ func (pool *TxPool) promoteExecutables(state *state.StateDB, accounts []common.A
pool
.
removeTx
(
tx
.
Hash
())
}
drop
-=
size
queuedR
L
Counter
.
Inc
(
int64
(
size
))
queuedR
ateLimit
Counter
.
Inc
(
int64
(
size
))
continue
}
// Otherwise drop only last few transactions
...
...
@@ -806,7 +844,7 @@ func (pool *TxPool) promoteExecutables(state *state.StateDB, accounts []common.A
for
i
:=
len
(
txs
)
-
1
;
i
>=
0
&&
drop
>
0
;
i
--
{
pool
.
removeTx
(
txs
[
i
]
.
Hash
())
drop
--
queuedR
L
Counter
.
Inc
(
1
)
queuedR
ateLimit
Counter
.
Inc
(
1
)
}
}
}
...
...
core/tx_pool_test.go
View file @
eebde1a2
This diff is collapsed.
Click to expand it.
light/txpool.go
View file @
eebde1a2
...
...
@@ -360,7 +360,7 @@ func (pool *TxPool) validateTx(ctx context.Context, tx *types.Transaction) error
currentState
:=
pool
.
currentState
()
if
n
,
err
:=
currentState
.
GetNonce
(
ctx
,
from
);
err
==
nil
{
if
n
>
tx
.
Nonce
()
{
return
core
.
ErrNonce
return
core
.
ErrNonce
TooLow
}
}
else
{
return
err
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment