diff options
author | Péter Szilágyi <peterke@gmail.com> | 2016-10-15 00:10:55 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-10-15 00:10:55 +0800 |
commit | a4d9e63d12c80a14294c0d085de6bf711ceec779 (patch) | |
tree | 8f491e499f1779ccdc2f4187d22f05fa151b2a27 /core/tx_pool.go | |
parent | 40cdcf1183df235e4b32cfdbf6182a00a0e49f24 (diff) | |
parent | 182d9cb752ffe08fc5e40718031bc8a497311ff5 (diff) | |
download | dexon-a4d9e63d12c80a14294c0d085de6bf711ceec779.tar dexon-a4d9e63d12c80a14294c0d085de6bf711ceec779.tar.gz dexon-a4d9e63d12c80a14294c0d085de6bf711ceec779.tar.bz2 dexon-a4d9e63d12c80a14294c0d085de6bf711ceec779.tar.lz dexon-a4d9e63d12c80a14294c0d085de6bf711ceec779.tar.xz dexon-a4d9e63d12c80a14294c0d085de6bf711ceec779.tar.zst dexon-a4d9e63d12c80a14294c0d085de6bf711ceec779.zip |
Merge pull request #3138 from karalabe/txpool-pending-limits
core: add global (soft) limits on the pending transactions
Diffstat (limited to 'core/tx_pool.go')
-rw-r--r-- | core/tx_pool.go | 65 |
1 files changed, 60 insertions, 5 deletions
diff --git a/core/tx_pool.go b/core/tx_pool.go index 4c9410d8e..2c8a5c396 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -30,6 +30,7 @@ import ( "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger/glog" + "gopkg.in/karalabe/cookiejar.v2/collections/prque" ) var ( @@ -46,10 +47,12 @@ var ( ) var ( - maxQueuedPerAccount = uint64(64) // Max limit of queued transactions per address - maxQueuedInTotal = uint64(8192) // Max limit of queued transactions from all accounts - maxQueuedLifetime = 3 * time.Hour // Max amount of time transactions from idle accounts are queued - evictionInterval = time.Minute // Time interval to check for evictable transactions + minPendingPerAccount = uint64(16) // Min number of guaranteed transaction slots per address + maxPendingTotal = uint64(4096) // Max limit of pending transactions from all accounts (soft) + maxQueuedPerAccount = uint64(64) // Max limit of queued transactions per address + maxQueuedInTotal = uint64(1024) // Max limit of queued transactions from all accounts + maxQueuedLifetime = 3 * time.Hour // Max amount of time transactions from idle accounts are queued + evictionInterval = time.Minute // Time interval to check for evictable transactions ) type stateFn func() (*state.StateDB, error) @@ -481,7 +484,6 @@ func (pool *TxPool) promoteExecutables() { } // Iterate over all accounts and promote any executable transactions queued := uint64(0) - for addr, list := range pool.queue { // Drop all transactions that are deemed too old (low nonce) for _, tx := range list.Forward(state.GetNonce(addr)) { @@ -519,6 +521,59 @@ func (pool *TxPool) promoteExecutables() { delete(pool.queue, addr) } } + // If the pending limit is overflown, start equalizing allowances + pending := uint64(0) + for _, list := range pool.pending { + pending += uint64(list.Len()) + } + if pending > maxPendingTotal { + // Assemble a spam order to penalize large transactors first + spammers := prque.New() + for addr, list := range pool.pending { + // Only evict transactions from high rollers + if uint64(list.Len()) > minPendingPerAccount { + // Skip local accounts as pools should maintain backlogs for themselves + for _, tx := range list.txs.items { + if !pool.localTx.contains(tx.Hash()) { + spammers.Push(addr, float32(list.Len())) + } + break // Checking on transaction for locality is enough + } + } + } + // Gradually drop transactions from offenders + offenders := []common.Address{} + for pending > maxPendingTotal && !spammers.Empty() { + // Retrieve the next offender if not local address + offender, _ := spammers.Pop() + offenders = append(offenders, offender.(common.Address)) + + // Equalize balances until all the same or below threshold + if len(offenders) > 1 { + // Calculate the equalization threshold for all current offenders + threshold := pool.pending[offender.(common.Address)].Len() + + // Iteratively reduce all offenders until below limit or threshold reached + for pending > maxPendingTotal && 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) + pending-- + } + } + } + } + // If still above threshold, reduce to limit or min allowance + if pending > maxPendingTotal && len(offenders) > 0 { + for pending > maxPendingTotal && uint64(pool.pending[offenders[len(offenders)-1]].Len()) > minPendingPerAccount { + for _, addr := range offenders { + list := pool.pending[addr] + list.Cap(list.Len() - 1) + pending-- + } + } + } + } // If we've queued more transactions than the hard limit, drop oldest ones if queued > maxQueuedInTotal { // Sort all accounts with queued transactions by heartbeat |