|
@@ -30,6 +30,7 @@ import (
|
|
|
"github.com/ethereum/go-ethereum/event"
|
|
"github.com/ethereum/go-ethereum/event"
|
|
|
"github.com/ethereum/go-ethereum/logger"
|
|
"github.com/ethereum/go-ethereum/logger"
|
|
|
"github.com/ethereum/go-ethereum/logger/glog"
|
|
"github.com/ethereum/go-ethereum/logger/glog"
|
|
|
|
|
+ "github.com/ethereum/go-ethereum/metrics"
|
|
|
"gopkg.in/karalabe/cookiejar.v2/collections/prque"
|
|
"gopkg.in/karalabe/cookiejar.v2/collections/prque"
|
|
|
)
|
|
)
|
|
|
|
|
|
|
@@ -55,6 +56,23 @@ var (
|
|
|
evictionInterval = time.Minute // Time interval to check for evictable transactions
|
|
evictionInterval = time.Minute // Time interval to check for evictable transactions
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
|
|
+var (
|
|
|
|
|
+ // Metrics for the pending pool
|
|
|
|
|
+ pendingDiscardCounter = metrics.NewCounter("txpool/pending/discard")
|
|
|
|
|
+ pendingReplaceCounter = metrics.NewCounter("txpool/pending/replace")
|
|
|
|
|
+ pendingRLCounter = 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")
|
|
|
|
|
+ queuedRLCounter = 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")
|
|
|
|
|
+)
|
|
|
|
|
+
|
|
|
type stateFn func() (*state.StateDB, error)
|
|
type stateFn func() (*state.StateDB, error)
|
|
|
|
|
|
|
|
// TxPool contains all currently known transactions. Transactions
|
|
// TxPool contains all currently known transactions. Transactions
|
|
@@ -306,6 +324,7 @@ func (pool *TxPool) add(tx *types.Transaction) error {
|
|
|
}
|
|
}
|
|
|
// Otherwise ensure basic validation passes and queue it up
|
|
// Otherwise ensure basic validation passes and queue it up
|
|
|
if err := pool.validateTx(tx); err != nil {
|
|
if err := pool.validateTx(tx); err != nil {
|
|
|
|
|
+ invalidTxCounter.Inc(1)
|
|
|
return err
|
|
return err
|
|
|
}
|
|
}
|
|
|
pool.enqueueTx(hash, tx)
|
|
pool.enqueueTx(hash, tx)
|
|
@@ -333,11 +352,13 @@ func (pool *TxPool) enqueueTx(hash common.Hash, tx *types.Transaction) {
|
|
|
}
|
|
}
|
|
|
inserted, old := pool.queue[from].Add(tx)
|
|
inserted, old := pool.queue[from].Add(tx)
|
|
|
if !inserted {
|
|
if !inserted {
|
|
|
|
|
+ queuedDiscardCounter.Inc(1)
|
|
|
return // An older transaction was better, discard this
|
|
return // An older transaction was better, discard this
|
|
|
}
|
|
}
|
|
|
// Discard any previous transaction and mark this
|
|
// Discard any previous transaction and mark this
|
|
|
if old != nil {
|
|
if old != nil {
|
|
|
delete(pool.all, old.Hash())
|
|
delete(pool.all, old.Hash())
|
|
|
|
|
+ queuedReplaceCounter.Inc(1)
|
|
|
}
|
|
}
|
|
|
pool.all[hash] = tx
|
|
pool.all[hash] = tx
|
|
|
}
|
|
}
|
|
@@ -360,11 +381,13 @@ func (pool *TxPool) promoteTx(addr common.Address, hash common.Hash, tx *types.T
|
|
|
if !inserted {
|
|
if !inserted {
|
|
|
// An older transaction was better, discard this
|
|
// An older transaction was better, discard this
|
|
|
delete(pool.all, hash)
|
|
delete(pool.all, hash)
|
|
|
|
|
+ pendingDiscardCounter.Inc(1)
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
// Otherwise discard any previous transaction and mark this
|
|
// Otherwise discard any previous transaction and mark this
|
|
|
if old != nil {
|
|
if old != nil {
|
|
|
delete(pool.all, old.Hash())
|
|
delete(pool.all, old.Hash())
|
|
|
|
|
+ pendingReplaceCounter.Inc(1)
|
|
|
}
|
|
}
|
|
|
pool.all[hash] = tx // Failsafe to work around direct pending inserts (tests)
|
|
pool.all[hash] = tx // Failsafe to work around direct pending inserts (tests)
|
|
|
|
|
|
|
@@ -499,6 +522,7 @@ func (pool *TxPool) promoteExecutables() {
|
|
|
glog.Infof("Removed unpayable queued transaction: %v", tx)
|
|
glog.Infof("Removed unpayable queued transaction: %v", tx)
|
|
|
}
|
|
}
|
|
|
delete(pool.all, tx.Hash())
|
|
delete(pool.all, tx.Hash())
|
|
|
|
|
+ queuedNofundsCounter.Inc(1)
|
|
|
}
|
|
}
|
|
|
// Gather all executable transactions and promote them
|
|
// Gather all executable transactions and promote them
|
|
|
for _, tx := range list.Ready(pool.pendingState.GetNonce(addr)) {
|
|
for _, tx := range list.Ready(pool.pendingState.GetNonce(addr)) {
|
|
@@ -513,6 +537,7 @@ func (pool *TxPool) promoteExecutables() {
|
|
|
glog.Infof("Removed cap-exceeding queued transaction: %v", tx)
|
|
glog.Infof("Removed cap-exceeding queued transaction: %v", tx)
|
|
|
}
|
|
}
|
|
|
delete(pool.all, tx.Hash())
|
|
delete(pool.all, tx.Hash())
|
|
|
|
|
+ queuedRLCounter.Inc(1)
|
|
|
}
|
|
}
|
|
|
queued += uint64(list.Len())
|
|
queued += uint64(list.Len())
|
|
|
|
|
|
|
@@ -527,6 +552,7 @@ func (pool *TxPool) promoteExecutables() {
|
|
|
pending += uint64(list.Len())
|
|
pending += uint64(list.Len())
|
|
|
}
|
|
}
|
|
|
if pending > maxPendingTotal {
|
|
if pending > maxPendingTotal {
|
|
|
|
|
+ pendingBeforeCap := pending
|
|
|
// Assemble a spam order to penalize large transactors first
|
|
// Assemble a spam order to penalize large transactors first
|
|
|
spammers := prque.New()
|
|
spammers := prque.New()
|
|
|
for addr, list := range pool.pending {
|
|
for addr, list := range pool.pending {
|
|
@@ -573,6 +599,7 @@ func (pool *TxPool) promoteExecutables() {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+ pendingRLCounter.Inc(int64(pendingBeforeCap - pending))
|
|
|
}
|
|
}
|
|
|
// If we've queued more transactions than the hard limit, drop oldest ones
|
|
// If we've queued more transactions than the hard limit, drop oldest ones
|
|
|
if queued > maxQueuedInTotal {
|
|
if queued > maxQueuedInTotal {
|
|
@@ -596,6 +623,7 @@ func (pool *TxPool) promoteExecutables() {
|
|
|
pool.removeTx(tx.Hash())
|
|
pool.removeTx(tx.Hash())
|
|
|
}
|
|
}
|
|
|
drop -= size
|
|
drop -= size
|
|
|
|
|
+ queuedRLCounter.Inc(int64(size))
|
|
|
continue
|
|
continue
|
|
|
}
|
|
}
|
|
|
// Otherwise drop only last few transactions
|
|
// Otherwise drop only last few transactions
|
|
@@ -603,6 +631,7 @@ func (pool *TxPool) promoteExecutables() {
|
|
|
for i := len(txs) - 1; i >= 0 && drop > 0; i-- {
|
|
for i := len(txs) - 1; i >= 0 && drop > 0; i-- {
|
|
|
pool.removeTx(txs[i].Hash())
|
|
pool.removeTx(txs[i].Hash())
|
|
|
drop--
|
|
drop--
|
|
|
|
|
+ queuedRLCounter.Inc(1)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -636,6 +665,7 @@ func (pool *TxPool) demoteUnexecutables() {
|
|
|
glog.Infof("Removed unpayable pending transaction: %v", tx)
|
|
glog.Infof("Removed unpayable pending transaction: %v", tx)
|
|
|
}
|
|
}
|
|
|
delete(pool.all, tx.Hash())
|
|
delete(pool.all, tx.Hash())
|
|
|
|
|
+ pendingNofundsCounter.Inc(1)
|
|
|
}
|
|
}
|
|
|
for _, tx := range invalids {
|
|
for _, tx := range invalids {
|
|
|
if glog.V(logger.Core) {
|
|
if glog.V(logger.Core) {
|