Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 22 additions & 2 deletions pkg/txm/storage/inmemory_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ const (
maxQueuedTransactions = 250
// pruneSubset controls the subset of confirmed transactions to prune when the structure reaches its max limit.
// i.e. if the value is 3 and the limit is 90, 30 transactions will be pruned.
pruneSubset = 3
pruneSubset = 3
pruneUnstartedTxDuration = 2 * time.Hour
)

type InMemoryStore struct {
Expand Down Expand Up @@ -269,15 +270,34 @@ func (m *InMemoryStore) UpdateTransactionBroadcast(txID uint64, txNonce uint64,
return nil
}

// Shouldn't call lock because it's being called by a method that already has the lock
func (m *InMemoryStore) pruneUnstartedTransactionsWithinDuration(threshold time.Duration) (txIDsToPrune []uint64) {
for i, tx := range m.UnstartedTransactions {
if time.Since(tx.CreatedAt) < threshold {
m.UnstartedTransactions = m.UnstartedTransactions[i:]
return txIDsToPrune
}
txIDsToPrune = append(txIDsToPrune, tx.ID)
delete(m.Transactions, tx.ID)
m.UnstartedTransactions[i] = nil // prevent memory leak
}
m.UnstartedTransactions = m.UnstartedTransactions[:0]
return
}

func (m *InMemoryStore) UpdateUnstartedTransactionWithNonce(nonce uint64) (*types.Transaction, error) {
m.Lock()
defer m.Unlock()

prunedTxIDs := m.pruneUnstartedTransactionsWithinDuration(pruneUnstartedTxDuration)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will panic. Needs to be before the check on line 299.

if len(prunedTxIDs) != 0 {
m.lggr.Debugf("Unstarted transactions map for address: %v exceeds cutoff time of: %s. Pruned %d oldest unstarted transactions. TxIDs: %v",
m.address, pruneUnstartedTxDuration, len(prunedTxIDs), prunedTxIDs)
}
if len(m.UnstartedTransactions) == 0 {
m.lggr.Debugf("Unstarted transactions queue is empty for address: %v", m.address)
return nil, nil
}

if tx, exists := m.UnconfirmedTransactions[nonce]; exists {
return nil, fmt.Errorf("an unconfirmed tx with the same nonce already exists: %v", tx)
}
Expand Down
22 changes: 21 additions & 1 deletion pkg/txm/storage/inmemory_store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,22 @@ func TestUpdateUnstartedTransactionWithNonce(t *testing.T) {
assert.Equal(t, txmgr.TxUnconfirmed, tx.State)
assert.Empty(t, m.UnstartedTransactions)
})

t.Run("prunes unstarted transaction beyond the cutoff duration", func(t *testing.T) {
var nonce uint64
m := NewInMemoryStore(logger.Test(t), fromAddress, testutils.FixtureChainID)
insertUnstartedTransactionCreatedAt(m, time.Now().Add(-3*pruneUnstartedTxDuration))
insertUnstartedTransactionCreatedAt(m, time.Now().Add(-2*pruneUnstartedTxDuration))
insertUnstartedTransactionCreatedAt(m, time.Now().Add(-1*pruneUnstartedTxDuration))
insertUnstartedTransactionCreatedAt(m, time.Now().Add(pruneUnstartedTxDuration/-2))
insertUnstartedTransaction(m)

tx, err := m.UpdateUnstartedTransactionWithNonce(nonce)
require.NoError(t, err)
assert.Equal(t, nonce, *tx.Nonce)
assert.Equal(t, txmgr.TxUnconfirmed, tx.State)
assert.Len(t, m.UnstartedTransactions, 1) // only the most recent one remains
})
}

func TestDeleteAttemptForUnconfirmedTx(t *testing.T) {
Expand Down Expand Up @@ -461,6 +477,10 @@ func TestPruneConfirmedTransactions(t *testing.T) {
}

func insertUnstartedTransaction(m *InMemoryStore) *types.Transaction {
return insertUnstartedTransactionCreatedAt(m, time.Now())
}

func insertUnstartedTransactionCreatedAt(m *InMemoryStore, createdAt time.Time) *types.Transaction {
m.Lock()
defer m.Unlock()

Expand All @@ -474,7 +494,7 @@ func insertUnstartedTransaction(m *InMemoryStore) *types.Transaction {
ToAddress: testutils.NewAddress(),
Value: big.NewInt(0),
SpecifiedGasLimit: 0,
CreatedAt: time.Now(),
CreatedAt: createdAt,
State: txmgr.TxUnstarted,
}

Expand Down
Loading