Skip to content

Commit

Permalink
Updated abandon tx to drop related attemtps
Browse files Browse the repository at this point in the history
  • Loading branch information
amit-momin committed Dec 10, 2024
1 parent 9d8d9f4 commit dec2671
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 5 deletions.
15 changes: 12 additions & 3 deletions core/chains/evm/txmgr/evm_tx_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -1786,8 +1786,17 @@ func (o *evmTxStore) Abandon(ctx context.Context, chainID *big.Int, addr common.
var cancel context.CancelFunc
ctx, cancel = o.stopCh.Ctx(ctx)
defer cancel()
_, err := o.q.ExecContext(ctx, `UPDATE evm.txes SET state='fatal_error', nonce = NULL, error = 'abandoned' WHERE state IN ('unconfirmed', 'in_progress', 'unstarted') AND evm_chain_id = $1 AND from_address = $2`, chainID.String(), addr)
return err
return o.Transact(ctx, false, func(orm *evmTxStore) error {
var abandonedIDs []string
err := orm.q.SelectContext(ctx, &abandonedIDs, `UPDATE evm.txes SET state='fatal_error', nonce = NULL, error = 'abandoned' WHERE state IN ('unconfirmed', 'in_progress', 'unstarted') AND evm_chain_id = $1 AND from_address = $2 RETURNING id`, chainID.String(), addr)
if err != nil {
return fmt.Errorf("failed to mark transactions as abandoned: %w", err)
}
if _, err := orm.q.ExecContext(ctx, `DELETE FROM evm.tx_attempts WHERE eth_tx_id = ANY($1)`, pq.Array(abandonedIDs)); err != nil {
return fmt.Errorf("failed to delete attempts related to abandoned transactions: %w", err)
}
return nil
})
}

// Find transactions by a field in the TxMeta blob and transaction states
Expand Down Expand Up @@ -1916,7 +1925,7 @@ func (o *evmTxStore) FindAttemptsRequiringReceiptFetch(ctx context.Context, chai
query := `
SELECT evm.tx_attempts.* FROM evm.tx_attempts
JOIN evm.txes ON evm.txes.ID = evm.tx_attempts.eth_tx_id
WHERE evm.tx_attempts.state = 'broadcast' AND evm.txes.state IN ('confirmed', 'confirmed_missing_receipt', 'fatal_error') AND evm.txes.evm_chain_id = $1 AND evm.txes.ID NOT IN (
WHERE evm.tx_attempts.state = 'broadcast' AND evm.txes.nonce IS NOT NULL AND evm.txes.state IN ('confirmed', 'confirmed_missing_receipt', 'fatal_error') AND evm.txes.evm_chain_id = $1 AND evm.txes.ID NOT IN (
SELECT DISTINCT evm.txes.ID FROM evm.txes
JOIN evm.tx_attempts ON evm.tx_attempts.eth_tx_id = evm.txes.ID
JOIN evm.receipts ON evm.receipts.tx_hash = evm.tx_attempts.hash
Expand Down
50 changes: 48 additions & 2 deletions core/chains/evm/txmgr/evm_tx_store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1796,11 +1796,16 @@ func TestORM_FindAttemptsRequiringReceiptFetch(t *testing.T) {
// Terminally stuck transaction with receipt should NOT be picked up for receipt fetch
stuckTx := mustInsertTerminallyStuckTxWithAttempt(t, txStore, fromAddress, 1, blockNum)
mustInsertEthReceipt(t, txStore, blockNum, utils.NewHash(), stuckTx.TxAttempts[0].Hash)
// Fatal transactions with nil nonce and stored attempts should NOT be picked up for receipt fetch
fatalTxWithAttempt := mustInsertFatalErrorEthTx(t, txStore, fromAddress)
attempt := newBroadcastLegacyEthTxAttempt(t, fatalTxWithAttempt.ID)
err := txStore.InsertTxAttempt(ctx, &attempt)
require.NoError(t, err)

// Confirmed transaction without receipt should be picked up for receipt fetch
confirmedTx := mustInsertConfirmedEthTx(t, txStore, 0, fromAddress)
attempt := newBroadcastLegacyEthTxAttempt(t, confirmedTx.ID)
err := txStore.InsertTxAttempt(ctx, &attempt)
attempt = newBroadcastLegacyEthTxAttempt(t, confirmedTx.ID)
err = txStore.InsertTxAttempt(ctx, &attempt)
require.NoError(t, err)

attempts, err := txStore.FindAttemptsRequiringReceiptFetch(ctx, testutils.FixtureChainID)
Expand All @@ -1823,6 +1828,12 @@ func TestORM_FindAttemptsRequiringReceiptFetch(t *testing.T) {
// Terminally stuck transaction with receipt should NOT be picked up for receipt fetch
stuckTxWithReceipt := mustInsertTerminallyStuckTxWithAttempt(t, txStore, fromAddress, 1, blockNum)
mustInsertEthReceipt(t, txStore, blockNum, utils.NewHash(), stuckTxWithReceipt.TxAttempts[0].Hash)
// Fatal transactions with nil nonce and stored attempts should NOT be picked up for receipt fetch
fatalTxWithAttempt := mustInsertFatalErrorEthTx(t, txStore, fromAddress)
attempt := newBroadcastLegacyEthTxAttempt(t, fatalTxWithAttempt.ID)
err := txStore.InsertTxAttempt(ctx, &attempt)
require.NoError(t, err)

// Terminally stuck transaction without receipt should be picked up for receipt fetch
stuckTxWoutReceipt := mustInsertTerminallyStuckTxWithAttempt(t, txStore, fromAddress, 0, blockNum)

Expand Down Expand Up @@ -2008,6 +2019,41 @@ func TestORM_DeleteReceiptsByTxHash(t *testing.T) {
require.Len(t, etx2.TxAttempts[0].Receipts, 1)
}

func TestORM_Abandon(t *testing.T) {
t.Parallel()

db := pgtest.NewSqlxDB(t)
txStore := cltest.NewTestTxStore(t, db)
ctx := tests.Context(t)
ethKeyStore := cltest.NewKeyStore(t, db).Eth()
_, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore)
etx1 := mustCreateUnstartedGeneratedTx(t, txStore, fromAddress, testutils.FixtureChainID)
etx2 := mustInsertInProgressEthTxWithAttempt(t, txStore, 1, fromAddress)
etx3 := mustInsertUnconfirmedEthTxWithAttemptState(t, txStore, 0, fromAddress, txmgrtypes.TxAttemptBroadcast)

err := txStore.Abandon(ctx, testutils.FixtureChainID, fromAddress)
require.NoError(t, err)

// transactions marked as fatal error with abandon reason, nil sequence, and no attempts
etx1, err = txStore.FindTxWithAttempts(ctx, etx1.ID)
require.NoError(t, err)
require.Equal(t, txmgrcommon.TxFatalError, etx1.State)
require.Nil(t, etx1.Sequence)
require.Empty(t, etx1.TxAttempts)

etx2, err = txStore.FindTxWithAttempts(ctx, etx2.ID)
require.NoError(t, err)
require.Equal(t, txmgrcommon.TxFatalError, etx2.State)
require.Nil(t, etx2.Sequence)
require.Empty(t, etx2.TxAttempts)

etx3, err = txStore.FindTxWithAttempts(ctx, etx3.ID)
require.NoError(t, err)
require.Equal(t, txmgrcommon.TxFatalError, etx3.State)
require.Nil(t, etx3.Sequence)
require.Empty(t, etx3.TxAttempts)
}

func mustInsertTerminallyStuckTxWithAttempt(t *testing.T, txStore txmgr.TestEvmTxStore, fromAddress common.Address, nonceInt int64, broadcastBeforeBlockNum int64) txmgr.Tx {
ctx := tests.Context(t)
broadcast := time.Now()
Expand Down

0 comments on commit dec2671

Please sign in to comment.