diff --git a/txcache/monitoring.go b/txcache/monitoring.go index 7d8ad284..17fd0368 100644 --- a/txcache/monitoring.go +++ b/txcache/monitoring.go @@ -12,10 +12,18 @@ import ( var log = logger.GetOrCreate("txcache") func (cache *TxCache) monitorEvictionWrtSenderLimit(sender []byte, evicted [][]byte) { - log.Trace("TxCache.AddTx() evict transactions wrt. limit by sender", "name", cache.name, "sender", sender, "num", len(evicted)) + log.Trace("TxCache.monitorEvictionWrtSenderLimit()", "name", cache.name, "sender", sender, "num", len(evicted)) for i := 0; i < core.MinInt(len(evicted), numEvictedTxsToDisplay); i++ { - log.Trace("TxCache.AddTx() evict transactions wrt. limit by sender", "name", cache.name, "sender", sender, "tx", evicted[i]) + log.Trace("TxCache.monitorEvictionWrtSenderLimit()", "name", cache.name, "sender", sender, "tx", evicted[i]) + } +} + +func (cache *TxCache) monitorEvictionWrtSenderNonce(sender []byte, senderNonce uint64, evicted [][]byte) { + log.Trace("TxCache.monitorEvictionWrtSenderNonce()", "name", cache.name, "sender", sender, "nonce", senderNonce, "num", len(evicted)) + + for i := 0; i < core.MinInt(len(evicted), numEvictedTxsToDisplay); i++ { + log.Trace("TxCache.monitorEvictionWrtSenderNonce()", "name", cache.name, "sender", sender, "nonce", senderNonce, "tx", evicted[i]) } } diff --git a/txcache/txCache.go b/txcache/txCache.go index d938b976..cfa31573 100644 --- a/txcache/txCache.go +++ b/txcache/txCache.go @@ -311,7 +311,12 @@ func (cache *TxCache) UnRegisterHandler(string) { // NotifyAccountNonce should be called by external components (such as interceptors and transactions processor) // in order to inform the cache about initial nonce gap phenomena func (cache *TxCache) NotifyAccountNonce(accountKey []byte, nonce uint64) { - cache.txListBySender.notifyAccountNonce(accountKey, nonce) + evicted := cache.txListBySender.notifyAccountNonce(accountKey, nonce) + + if len(evicted) > 0 { + cache.monitorEvictionWrtSenderNonce(accountKey, nonce, evicted) + cache.txByHash.RemoveTxsBulk(evicted) + } } // ImmunizeTxsAgainstEviction does nothing for this type of cache diff --git a/txcache/txListBySenderMap.go b/txcache/txListBySenderMap.go index ccda1ce0..beb9f2fd 100644 --- a/txcache/txListBySenderMap.go +++ b/txcache/txListBySenderMap.go @@ -133,14 +133,14 @@ func (txMap *txListBySenderMap) RemoveSendersBulk(senders []string) uint32 { return numRemoved } -func (txMap *txListBySenderMap) notifyAccountNonce(accountKey []byte, nonce uint64) { +func (txMap *txListBySenderMap) notifyAccountNonce(accountKey []byte, nonce uint64) [][]byte { sender := string(accountKey) listForSender, ok := txMap.getListForSender(sender) if !ok { - return + return nil } - listForSender.notifyAccountNonce(nonce) + return listForSender.notifyAccountNonce(nonce) } func (txMap *txListBySenderMap) getSnapshotAscending() []*txListForSender { diff --git a/txcache/txListForSender.go b/txcache/txListForSender.go index a12a91d1..99fcd819 100644 --- a/txcache/txListForSender.go +++ b/txcache/txListForSender.go @@ -320,9 +320,37 @@ func approximatelyCountTxInLists(lists []*txListForSender) uint64 { // notifyAccountNonce does not update the "numFailedSelections" counter, // since the notification comes at a time when we cannot actually detect whether the initial gap still exists or it was resolved. -func (listForSender *txListForSender) notifyAccountNonce(nonce uint64) { +// Removes transactions with lower nonces and returns their hashes. +func (listForSender *txListForSender) notifyAccountNonce(nonce uint64) [][]byte { + listForSender.mutex.Lock() + defer listForSender.mutex.Unlock() + listForSender.accountNonce.Set(nonce) _ = listForSender.accountNonceKnown.SetReturningPrevious() + + return listForSender.evictTransactionsWithLowerNonces(nonce) +} + +// This function should only be used in critical section (listForSender.mutex) +func (listForSender *txListForSender) evictTransactionsWithLowerNonces(accountNonce uint64) [][]byte { + evictedTxHashes := make([][]byte, 0) + + for element := listForSender.items.Front(); element != nil; element = element.Next() { + tx := element.Value.(*WrappedTransaction) + txNonce := tx.Tx.GetNonce() + + if txNonce >= accountNonce { + break + } + + listForSender.items.Remove(element) + listForSender.onRemovedListElement(element) + + // Keep track of removed transactions + evictedTxHashes = append(evictedTxHashes, tx.TxHash) + } + + return evictedTxHashes } // This function should only be used in critical section (listForSender.mutex)