From 408ea927aeb784848aea2ec1cb725ec522c30a42 Mon Sep 17 00:00:00 2001 From: colinlyguo Date: Fri, 29 Nov 2024 02:01:46 +0800 Subject: [PATCH 1/9] fix(rollup-relayer): graceful restart --- common/types/db.go | 4 +++ rollup/internal/controller/sender/sender.go | 31 +++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/common/types/db.go b/common/types/db.go index b05aea2eb3..a57f87ac8a 100644 --- a/common/types/db.go +++ b/common/types/db.go @@ -310,6 +310,8 @@ const ( TxStatusConfirmed // TxStatusConfirmedFailed indicates that the transaction has failed during processing. TxStatusConfirmedFailed + // TxStatusSentFailed indicates that the transaction has failed to be sent. + TxStatusSentFailed ) func (s TxStatus) String() string { @@ -322,6 +324,8 @@ func (s TxStatus) String() string { return "TxStatusConfirmed" case TxStatusConfirmedFailed: return "TxStatusConfirmedFailed" + case TxStatusSentFailed: + return "TxStatusSentFailed" default: return fmt.Sprintf("Unknown TxStatus (%d)", int32(s)) } diff --git a/rollup/internal/controller/sender/sender.go b/rollup/internal/controller/sender/sender.go index 9c8652d335..0aafcdfd6c 100644 --- a/rollup/internal/controller/sender/sender.go +++ b/rollup/internal/controller/sender/sender.go @@ -232,6 +232,11 @@ func (s *Sender) SendTransaction(contextID string, target *common.Address, data } if err := s.client.SendTransaction(s.ctx, signedTx); err != nil { + // SendTransaction failed, mark the transaction as failed + if updateErr := s.pendingTransactionOrm.UpdatePendingTransactionStatusByTxHash(s.ctx, signedTx.Hash(), types.TxStatusSentFailed, nil); updateErr != nil { + log.Error("failed to mark transaction as sent failed", "tx hash", signedTx.Hash().String(), "from", s.transactionSigner.GetAddr().String(), "nonce", signedTx.Nonce(), "sendTxErr", err, "updateErr", updateErr) + } + log.Error("failed to send tx", "tx hash", signedTx.Hash().String(), "from", s.transactionSigner.GetAddr().String(), "nonce", signedTx.Nonce(), "err", err) // Check if contain nonce, and reset nonce // only reset nonce when it is not from resubmit @@ -458,6 +463,15 @@ func (s *Sender) createReplacingTransaction(tx *gethTypes.Transaction, baseFee, blobGasFeeCap = maxBlobGasPrice } + // Check if any fee cap is less than double + doubledTipCap := new(big.Int).Mul(originalGasTipCap, big.NewInt(2)) + doubledFeeCap := new(big.Int).Mul(originalGasFeeCap, big.NewInt(2)) + doubledBlobFeeCap := new(big.Int).Mul(originalBlobGasFeeCap, big.NewInt(2)) + if gasTipCap.Cmp(doubledTipCap) < 0 || gasFeeCap.Cmp(doubledFeeCap) < 0 || blobGasFeeCap.Cmp(doubledBlobFeeCap) < 0 { + log.Error("gas fees must be at least double", "originalTipCap", originalGasTipCap, "currentTipCap", gasTipCap, "requiredTipCap", doubledTipCap, "originalFeeCap", originalGasFeeCap, "currentFeeCap", gasFeeCap, "requiredFeeCap", doubledFeeCap, "originalBlobFeeCap", originalBlobGasFeeCap, "currentBlobFeeCap", blobGasFeeCap, "requiredBlobFeeCap", doubledBlobFeeCap) + return nil, errors.New("gas fees must be at least double") + } + feeData.gasFeeCap = gasFeeCap feeData.gasTipCap = gasTipCap feeData.blobGasFeeCap = blobGasFeeCap @@ -608,6 +622,23 @@ func (s *Sender) checkPendingTransaction() { } if err := s.client.SendTransaction(s.ctx, newSignedTx); err != nil { + // SendTransaction failed, need to rollback the previous database changes + if rollbackErr := s.db.Transaction(func(tx *gorm.DB) error { + // Restore original transaction status back to pending + if updateErr := s.pendingTransactionOrm.UpdatePendingTransactionStatusByTxHash(s.ctx, originalTx.Hash(), types.TxStatusPending, tx); updateErr != nil { + return fmt.Errorf("failed to rollback status of original transaction, err: %w", updateErr) + } + // Mark the new transaction as sent failed instead of deleting it + if updateErr := s.pendingTransactionOrm.UpdatePendingTransactionStatusByTxHash(s.ctx, newSignedTx.Hash(), types.TxStatusSentFailed, tx); updateErr != nil { + return fmt.Errorf("failed to mark transaction as sent failed, err: %w", updateErr) + } + return nil + }); rollbackErr != nil { + // Both SendTransaction and rollback failed + log.Error("failed to rollback database after SendTransaction failed", "tx hash", newSignedTx.Hash().String(), "from", s.transactionSigner.GetAddr().String(), "nonce", newSignedTx.Nonce(), "sendTxErr", err, "rollbackErr", rollbackErr) + return + } + log.Error("failed to send replacing tx", "tx hash", newSignedTx.Hash().String(), "from", s.transactionSigner.GetAddr().String(), "nonce", newSignedTx.Nonce(), "err", err) return } From 83718432170bb0847fc9781d86aa72b06142776d Mon Sep 17 00:00:00 2001 From: colinlyguo Date: Thu, 28 Nov 2024 18:02:57 +0000 Subject: [PATCH 2/9] =?UTF-8?q?chore:=20auto=20version=20bump=E2=80=89[bot?= =?UTF-8?q?]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common/version/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/version/version.go b/common/version/version.go index 6fdb62be47..a88911a89f 100644 --- a/common/version/version.go +++ b/common/version/version.go @@ -5,7 +5,7 @@ import ( "runtime/debug" ) -var tag = "v4.4.78" +var tag = "v4.4.79" var commit = func() string { if info, ok := debug.ReadBuildInfo(); ok { From 158ff6b3efb10aa51869d580086cb17c41df82a7 Mon Sep 17 00:00:00 2001 From: colinlyguo Date: Fri, 29 Nov 2024 02:31:16 +0800 Subject: [PATCH 3/9] return error --- rollup/internal/controller/sender/sender.go | 1 + 1 file changed, 1 insertion(+) diff --git a/rollup/internal/controller/sender/sender.go b/rollup/internal/controller/sender/sender.go index 0aafcdfd6c..668510cfe6 100644 --- a/rollup/internal/controller/sender/sender.go +++ b/rollup/internal/controller/sender/sender.go @@ -235,6 +235,7 @@ func (s *Sender) SendTransaction(contextID string, target *common.Address, data // SendTransaction failed, mark the transaction as failed if updateErr := s.pendingTransactionOrm.UpdatePendingTransactionStatusByTxHash(s.ctx, signedTx.Hash(), types.TxStatusSentFailed, nil); updateErr != nil { log.Error("failed to mark transaction as sent failed", "tx hash", signedTx.Hash().String(), "from", s.transactionSigner.GetAddr().String(), "nonce", signedTx.Nonce(), "sendTxErr", err, "updateErr", updateErr) + return common.Hash{}, fmt.Errorf("failed to mark transaction as sent failed, err: %w", updateErr) } log.Error("failed to send tx", "tx hash", signedTx.Hash().String(), "from", s.transactionSigner.GetAddr().String(), "nonce", signedTx.Nonce(), "err", err) From 2eb726661ac190f9803f45d2fd577ab604202232 Mon Sep 17 00:00:00 2001 From: colinlyguo Date: Fri, 29 Nov 2024 03:03:13 +0800 Subject: [PATCH 4/9] use delete instead of update --- common/types/db.go | 4 ---- rollup/internal/controller/sender/sender.go | 14 +++++++------- rollup/internal/orm/pending_transaction.go | 16 ++++++++++++++++ 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/common/types/db.go b/common/types/db.go index a57f87ac8a..b05aea2eb3 100644 --- a/common/types/db.go +++ b/common/types/db.go @@ -310,8 +310,6 @@ const ( TxStatusConfirmed // TxStatusConfirmedFailed indicates that the transaction has failed during processing. TxStatusConfirmedFailed - // TxStatusSentFailed indicates that the transaction has failed to be sent. - TxStatusSentFailed ) func (s TxStatus) String() string { @@ -324,8 +322,6 @@ func (s TxStatus) String() string { return "TxStatusConfirmed" case TxStatusConfirmedFailed: return "TxStatusConfirmedFailed" - case TxStatusSentFailed: - return "TxStatusSentFailed" default: return fmt.Sprintf("Unknown TxStatus (%d)", int32(s)) } diff --git a/rollup/internal/controller/sender/sender.go b/rollup/internal/controller/sender/sender.go index 668510cfe6..f1b5a3fb52 100644 --- a/rollup/internal/controller/sender/sender.go +++ b/rollup/internal/controller/sender/sender.go @@ -232,10 +232,10 @@ func (s *Sender) SendTransaction(contextID string, target *common.Address, data } if err := s.client.SendTransaction(s.ctx, signedTx); err != nil { - // SendTransaction failed, mark the transaction as failed - if updateErr := s.pendingTransactionOrm.UpdatePendingTransactionStatusByTxHash(s.ctx, signedTx.Hash(), types.TxStatusSentFailed, nil); updateErr != nil { - log.Error("failed to mark transaction as sent failed", "tx hash", signedTx.Hash().String(), "from", s.transactionSigner.GetAddr().String(), "nonce", signedTx.Nonce(), "sendTxErr", err, "updateErr", updateErr) - return common.Hash{}, fmt.Errorf("failed to mark transaction as sent failed, err: %w", updateErr) + // Delete the transaction from the pending transaction table if it fails to send. + if updateErr := s.pendingTransactionOrm.DeletePendingTransactionByTxHash(s.ctx, signedTx.Hash()); updateErr != nil { + log.Error("failed to delete transaction", "tx hash", signedTx.Hash().String(), "from", s.transactionSigner.GetAddr().String(), "nonce", signedTx.Nonce(), "err", updateErr) + return common.Hash{}, fmt.Errorf("failed to delete transaction, err: %w", updateErr) } log.Error("failed to send tx", "tx hash", signedTx.Hash().String(), "from", s.transactionSigner.GetAddr().String(), "nonce", signedTx.Nonce(), "err", err) @@ -629,9 +629,9 @@ func (s *Sender) checkPendingTransaction() { if updateErr := s.pendingTransactionOrm.UpdatePendingTransactionStatusByTxHash(s.ctx, originalTx.Hash(), types.TxStatusPending, tx); updateErr != nil { return fmt.Errorf("failed to rollback status of original transaction, err: %w", updateErr) } - // Mark the new transaction as sent failed instead of deleting it - if updateErr := s.pendingTransactionOrm.UpdatePendingTransactionStatusByTxHash(s.ctx, newSignedTx.Hash(), types.TxStatusSentFailed, tx); updateErr != nil { - return fmt.Errorf("failed to mark transaction as sent failed, err: %w", updateErr) + // Delete the new transaction that was inserted + if updateErr := s.pendingTransactionOrm.DeletePendingTransactionByTxHash(s.ctx, newSignedTx.Hash(), tx); updateErr != nil { + return fmt.Errorf("failed to delete new transaction, err: %w", updateErr) } return nil }); rollbackErr != nil { diff --git a/rollup/internal/orm/pending_transaction.go b/rollup/internal/orm/pending_transaction.go index 3c73ed13eb..7ae640b7ad 100644 --- a/rollup/internal/orm/pending_transaction.go +++ b/rollup/internal/orm/pending_transaction.go @@ -150,6 +150,22 @@ func (o *PendingTransaction) InsertPendingTransaction(ctx context.Context, conte return nil } +// DeletePendingTransactionByTxHash deletes a pending transaction record from the database by transaction hash. +func (o *PendingTransaction) DeletePendingTransactionByTxHash(ctx context.Context, hash common.Hash, dbTX ...*gorm.DB) error { + db := o.db + if len(dbTX) > 0 && dbTX[0] != nil { + db = dbTX[0] + } + db = db.WithContext(ctx) + db = db.Model(&PendingTransaction{}) + + result := db.Where("hash = ?", hash.String()).Delete(&PendingTransaction{}) + if result.Error != nil { + return fmt.Errorf("failed to delete pending transaction, err: %w", result.Error) + } + return nil +} + // UpdatePendingTransactionStatusByTxHash updates the status of a transaction based on the transaction hash. func (o *PendingTransaction) UpdatePendingTransactionStatusByTxHash(ctx context.Context, hash common.Hash, status types.TxStatus, dbTX ...*gorm.DB) error { db := o.db From 0866f99416879857dddf24624e6e9e59dc71f7b4 Mon Sep 17 00:00:00 2001 From: colinlyguo Date: Fri, 29 Nov 2024 03:17:25 +0800 Subject: [PATCH 5/9] address AI's comments --- rollup/internal/orm/pending_transaction.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/rollup/internal/orm/pending_transaction.go b/rollup/internal/orm/pending_transaction.go index 7ae640b7ad..14f9258fbe 100644 --- a/rollup/internal/orm/pending_transaction.go +++ b/rollup/internal/orm/pending_transaction.go @@ -163,6 +163,9 @@ func (o *PendingTransaction) DeletePendingTransactionByTxHash(ctx context.Contex if result.Error != nil { return fmt.Errorf("failed to delete pending transaction, err: %w", result.Error) } + if result.RowsAffected == 0 { + return fmt.Errorf("no pending transaction found with hash: %s", hash.String()) + } return nil } From 538e7d10e9c3f4735f972f7333eba6f177b25485 Mon Sep 17 00:00:00 2001 From: colinlyguo Date: Mon, 2 Dec 2024 14:29:22 +0800 Subject: [PATCH 6/9] refactor: rename --- rollup/internal/controller/sender/sender.go | 10 +++++----- rollup/internal/orm/orm_test.go | 4 ++-- rollup/internal/orm/pending_transaction.go | 10 +++++----- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/rollup/internal/controller/sender/sender.go b/rollup/internal/controller/sender/sender.go index f1b5a3fb52..a36be19123 100644 --- a/rollup/internal/controller/sender/sender.go +++ b/rollup/internal/controller/sender/sender.go @@ -233,7 +233,7 @@ func (s *Sender) SendTransaction(contextID string, target *common.Address, data if err := s.client.SendTransaction(s.ctx, signedTx); err != nil { // Delete the transaction from the pending transaction table if it fails to send. - if updateErr := s.pendingTransactionOrm.DeletePendingTransactionByTxHash(s.ctx, signedTx.Hash()); updateErr != nil { + if updateErr := s.pendingTransactionOrm.DeleteTransactionByTxHash(s.ctx, signedTx.Hash()); updateErr != nil { log.Error("failed to delete transaction", "tx hash", signedTx.Hash().String(), "from", s.transactionSigner.GetAddr().String(), "nonce", signedTx.Nonce(), "err", updateErr) return common.Hash{}, fmt.Errorf("failed to delete transaction, err: %w", updateErr) } @@ -535,7 +535,7 @@ func (s *Sender) checkPendingTransaction() { if receipt.BlockNumber.Uint64() <= confirmed { if dbTxErr := s.db.Transaction(func(dbTX *gorm.DB) error { // Update the status of the transaction to TxStatusConfirmed. - if updateErr := s.pendingTransactionOrm.UpdatePendingTransactionStatusByTxHash(s.ctx, originalTx.Hash(), types.TxStatusConfirmed, dbTX); updateErr != nil { + if updateErr := s.pendingTransactionOrm.UpdateTransactionStatusByTxHash(s.ctx, originalTx.Hash(), types.TxStatusConfirmed, dbTX); updateErr != nil { log.Error("failed to update transaction status by tx hash", "hash", originalTx.Hash().String(), "sender meta", s.getSenderMeta(), "from", s.transactionSigner.GetAddr().String(), "nonce", originalTx.Nonce(), "err", updateErr) return updateErr } @@ -610,7 +610,7 @@ func (s *Sender) checkPendingTransaction() { // A corner case is that the transaction is inserted into the table but not sent to the chain, because the server is stopped in the middle. // This case will be handled by the checkPendingTransaction function. if dbTxErr := s.db.Transaction(func(dbTX *gorm.DB) error { - if updateErr := s.pendingTransactionOrm.UpdatePendingTransactionStatusByTxHash(s.ctx, originalTx.Hash(), types.TxStatusReplaced, dbTX); updateErr != nil { + if updateErr := s.pendingTransactionOrm.UpdateTransactionStatusByTxHash(s.ctx, originalTx.Hash(), types.TxStatusReplaced, dbTX); updateErr != nil { return fmt.Errorf("failed to update status of transaction with hash %s to TxStatusReplaced, err: %w", newSignedTx.Hash().String(), updateErr) } if updateErr := s.pendingTransactionOrm.InsertPendingTransaction(s.ctx, txnToCheck.ContextID, s.getSenderMeta(), newSignedTx, blockNumber, dbTX); updateErr != nil { @@ -626,11 +626,11 @@ func (s *Sender) checkPendingTransaction() { // SendTransaction failed, need to rollback the previous database changes if rollbackErr := s.db.Transaction(func(tx *gorm.DB) error { // Restore original transaction status back to pending - if updateErr := s.pendingTransactionOrm.UpdatePendingTransactionStatusByTxHash(s.ctx, originalTx.Hash(), types.TxStatusPending, tx); updateErr != nil { + if updateErr := s.pendingTransactionOrm.UpdateTransactionStatusByTxHash(s.ctx, originalTx.Hash(), types.TxStatusPending, tx); updateErr != nil { return fmt.Errorf("failed to rollback status of original transaction, err: %w", updateErr) } // Delete the new transaction that was inserted - if updateErr := s.pendingTransactionOrm.DeletePendingTransactionByTxHash(s.ctx, newSignedTx.Hash(), tx); updateErr != nil { + if updateErr := s.pendingTransactionOrm.DeleteTransactionByTxHash(s.ctx, newSignedTx.Hash(), tx); updateErr != nil { return fmt.Errorf("failed to delete new transaction, err: %w", updateErr) } return nil diff --git a/rollup/internal/orm/orm_test.go b/rollup/internal/orm/orm_test.go index f16274370f..58684b744e 100644 --- a/rollup/internal/orm/orm_test.go +++ b/rollup/internal/orm/orm_test.go @@ -560,7 +560,7 @@ func TestPendingTransactionOrm(t *testing.T) { err = pendingTransactionOrm.InsertPendingTransaction(context.Background(), "test", senderMeta, tx1, 0) assert.NoError(t, err) - err = pendingTransactionOrm.UpdatePendingTransactionStatusByTxHash(context.Background(), tx0.Hash(), types.TxStatusReplaced) + err = pendingTransactionOrm.UpdateTransactionStatusByTxHash(context.Background(), tx0.Hash(), types.TxStatusReplaced) assert.NoError(t, err) txs, err := pendingTransactionOrm.GetPendingOrReplacedTransactionsBySenderType(context.Background(), senderMeta.Type, 2) @@ -577,7 +577,7 @@ func TestPendingTransactionOrm(t *testing.T) { assert.Equal(t, senderMeta.Address.String(), txs[1].SenderAddress) assert.Equal(t, senderMeta.Type, txs[1].SenderType) - err = pendingTransactionOrm.UpdatePendingTransactionStatusByTxHash(context.Background(), tx1.Hash(), types.TxStatusConfirmed) + err = pendingTransactionOrm.UpdateTransactionStatusByTxHash(context.Background(), tx1.Hash(), types.TxStatusConfirmed) assert.NoError(t, err) txs, err = pendingTransactionOrm.GetPendingOrReplacedTransactionsBySenderType(context.Background(), senderMeta.Type, 2) diff --git a/rollup/internal/orm/pending_transaction.go b/rollup/internal/orm/pending_transaction.go index 14f9258fbe..4e57028237 100644 --- a/rollup/internal/orm/pending_transaction.go +++ b/rollup/internal/orm/pending_transaction.go @@ -150,8 +150,8 @@ func (o *PendingTransaction) InsertPendingTransaction(ctx context.Context, conte return nil } -// DeletePendingTransactionByTxHash deletes a pending transaction record from the database by transaction hash. -func (o *PendingTransaction) DeletePendingTransactionByTxHash(ctx context.Context, hash common.Hash, dbTX ...*gorm.DB) error { +// DeleteTransactionByTxHash deletes a transaction record from the database by transaction hash. +func (o *PendingTransaction) DeleteTransactionByTxHash(ctx context.Context, hash common.Hash, dbTX ...*gorm.DB) error { db := o.db if len(dbTX) > 0 && dbTX[0] != nil { db = dbTX[0] @@ -169,8 +169,8 @@ func (o *PendingTransaction) DeletePendingTransactionByTxHash(ctx context.Contex return nil } -// UpdatePendingTransactionStatusByTxHash updates the status of a transaction based on the transaction hash. -func (o *PendingTransaction) UpdatePendingTransactionStatusByTxHash(ctx context.Context, hash common.Hash, status types.TxStatus, dbTX ...*gorm.DB) error { +// UpdateTransactionStatusByTxHash updates the status of a transaction based on the transaction hash. +func (o *PendingTransaction) UpdateTransactionStatusByTxHash(ctx context.Context, hash common.Hash, status types.TxStatus, dbTX ...*gorm.DB) error { db := o.db if len(dbTX) > 0 && dbTX[0] != nil { db = dbTX[0] @@ -179,7 +179,7 @@ func (o *PendingTransaction) UpdatePendingTransactionStatusByTxHash(ctx context. db = db.Model(&PendingTransaction{}) db = db.Where("hash = ?", hash.String()) if err := db.Update("status", status).Error; err != nil { - return fmt.Errorf("failed to UpdatePendingTransactionStatusByTxHash, txHash: %s, error: %w", hash, err) + return fmt.Errorf("failed to UpdateTransactionStatusByTxHash, txHash: %s, error: %w", hash, err) } return nil } From feb3294d71ab79977647484756bb42925dc3bae6 Mon Sep 17 00:00:00 2001 From: colinlyguo Date: Mon, 2 Dec 2024 15:51:47 +0800 Subject: [PATCH 7/9] add a warn log to track deletion --- rollup/internal/orm/pending_transaction.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rollup/internal/orm/pending_transaction.go b/rollup/internal/orm/pending_transaction.go index 4e57028237..3fe72d9714 100644 --- a/rollup/internal/orm/pending_transaction.go +++ b/rollup/internal/orm/pending_transaction.go @@ -8,6 +8,7 @@ import ( "github.com/scroll-tech/go-ethereum/common" gethTypes "github.com/scroll-tech/go-ethereum/core/types" + "github.com/scroll-tech/go-ethereum/log" "gorm.io/gorm" "scroll-tech/common/types" @@ -166,6 +167,9 @@ func (o *PendingTransaction) DeleteTransactionByTxHash(ctx context.Context, hash if result.RowsAffected == 0 { return fmt.Errorf("no pending transaction found with hash: %s", hash.String()) } + if result.RowsAffected > 0 { + log.Warn("Successfully deleted pending transaction", "hash", hash.String()) + } return nil } From 528c89d00ba6215df05ae65986f2a8a2bbb07314 Mon Sep 17 00:00:00 2001 From: colinlyguo Date: Mon, 2 Dec 2024 18:32:08 +0800 Subject: [PATCH 8/9] use permanently delete instead of soft delete && add unit tests --- rollup/internal/orm/orm_test.go | 13 +++++++++++++ rollup/internal/orm/pending_transaction.go | 13 ++++++++----- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/rollup/internal/orm/orm_test.go b/rollup/internal/orm/orm_test.go index 58684b744e..52e70df2c6 100644 --- a/rollup/internal/orm/orm_test.go +++ b/rollup/internal/orm/orm_test.go @@ -594,4 +594,17 @@ func TestPendingTransactionOrm(t *testing.T) { status, err := pendingTransactionOrm.GetTxStatusByTxHash(context.Background(), tx0.Hash()) assert.NoError(t, err) assert.Equal(t, types.TxStatusConfirmedFailed, status) + + // Test DeleteTransactionByTxHash + err = pendingTransactionOrm.DeleteTransactionByTxHash(context.Background(), tx0.Hash()) + assert.NoError(t, err) + + // Verify the transaction is deleted + status, err = pendingTransactionOrm.GetTxStatusByTxHash(context.Background(), tx0.Hash()) + assert.NoError(t, err) + assert.Equal(t, types.TxStatusUnknown, status) // Should return unknown status for deleted transaction + + // Try to delete non-existent transaction + err = pendingTransactionOrm.DeleteTransactionByTxHash(context.Background(), common.HexToHash("0x123")) + assert.Error(t, err) // Should return error for non-existent transaction } diff --git a/rollup/internal/orm/pending_transaction.go b/rollup/internal/orm/pending_transaction.go index 3fe72d9714..c4dd025b8d 100644 --- a/rollup/internal/orm/pending_transaction.go +++ b/rollup/internal/orm/pending_transaction.go @@ -151,7 +151,9 @@ func (o *PendingTransaction) InsertPendingTransaction(ctx context.Context, conte return nil } -// DeleteTransactionByTxHash deletes a transaction record from the database by transaction hash. +// DeleteTransactionByTxHash permanently deletes a transaction record from the database by transaction hash. +// Using hard delete instead of soft delete to prevent database bloat, as repeated SendTransaction failures +// could write a large number of transactions to the database. func (o *PendingTransaction) DeleteTransactionByTxHash(ctx context.Context, hash common.Hash, dbTX ...*gorm.DB) error { db := o.db if len(dbTX) > 0 && dbTX[0] != nil { @@ -160,15 +162,16 @@ func (o *PendingTransaction) DeleteTransactionByTxHash(ctx context.Context, hash db = db.WithContext(ctx) db = db.Model(&PendingTransaction{}) - result := db.Where("hash = ?", hash.String()).Delete(&PendingTransaction{}) + // Perform hard delete by using Unscoped() + result := db.Where("hash = ?", hash.String()).Unscoped().Delete(&PendingTransaction{}) if result.Error != nil { - return fmt.Errorf("failed to delete pending transaction, err: %w", result.Error) + return fmt.Errorf("failed to delete transaction, err: %w", result.Error) } if result.RowsAffected == 0 { - return fmt.Errorf("no pending transaction found with hash: %s", hash.String()) + return fmt.Errorf("no transaction found with hash: %s", hash.String()) } if result.RowsAffected > 0 { - log.Warn("Successfully deleted pending transaction", "hash", hash.String()) + log.Warn("Successfully deleted transaction", "hash", hash.String()) } return nil } From b527cd5d32826e2e8b4799e208a651b2554aa896 Mon Sep 17 00:00:00 2001 From: colinlyguo Date: Mon, 2 Dec 2024 18:34:00 +0800 Subject: [PATCH 9/9] tweak comments --- rollup/internal/orm/pending_transaction.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rollup/internal/orm/pending_transaction.go b/rollup/internal/orm/pending_transaction.go index c4dd025b8d..df53682704 100644 --- a/rollup/internal/orm/pending_transaction.go +++ b/rollup/internal/orm/pending_transaction.go @@ -152,7 +152,7 @@ func (o *PendingTransaction) InsertPendingTransaction(ctx context.Context, conte } // DeleteTransactionByTxHash permanently deletes a transaction record from the database by transaction hash. -// Using hard delete instead of soft delete to prevent database bloat, as repeated SendTransaction failures +// Using permanent delete (Unscoped) instead of soft delete to prevent database bloat, as repeated SendTransaction failures // could write a large number of transactions to the database. func (o *PendingTransaction) DeleteTransactionByTxHash(ctx context.Context, hash common.Hash, dbTX ...*gorm.DB) error { db := o.db @@ -162,7 +162,7 @@ func (o *PendingTransaction) DeleteTransactionByTxHash(ctx context.Context, hash db = db.WithContext(ctx) db = db.Model(&PendingTransaction{}) - // Perform hard delete by using Unscoped() + // Perform permanent delete by using Unscoped() result := db.Where("hash = ?", hash.String()).Unscoped().Delete(&PendingTransaction{}) if result.Error != nil { return fmt.Errorf("failed to delete transaction, err: %w", result.Error)