@@ -232,6 +232,12 @@ func (s *Sender) SendTransaction(contextID string, target *common.Address, data
232232 }
233233
234234 if err := s .client .SendTransaction (s .ctx , signedTx ); err != nil {
235+ // Delete the transaction from the pending transaction table if it fails to send.
236+ if updateErr := s .pendingTransactionOrm .DeleteTransactionByTxHash (s .ctx , signedTx .Hash ()); updateErr != nil {
237+ log .Error ("failed to delete transaction" , "tx hash" , signedTx .Hash ().String (), "from" , s .transactionSigner .GetAddr ().String (), "nonce" , signedTx .Nonce (), "err" , updateErr )
238+ return common.Hash {}, fmt .Errorf ("failed to delete transaction, err: %w" , updateErr )
239+ }
240+
235241 log .Error ("failed to send tx" , "tx hash" , signedTx .Hash ().String (), "from" , s .transactionSigner .GetAddr ().String (), "nonce" , signedTx .Nonce (), "err" , err )
236242 // Check if contain nonce, and reset nonce
237243 // only reset nonce when it is not from resubmit
@@ -458,6 +464,15 @@ func (s *Sender) createReplacingTransaction(tx *gethTypes.Transaction, baseFee,
458464 blobGasFeeCap = maxBlobGasPrice
459465 }
460466
467+ // Check if any fee cap is less than double
468+ doubledTipCap := new (big.Int ).Mul (originalGasTipCap , big .NewInt (2 ))
469+ doubledFeeCap := new (big.Int ).Mul (originalGasFeeCap , big .NewInt (2 ))
470+ doubledBlobFeeCap := new (big.Int ).Mul (originalBlobGasFeeCap , big .NewInt (2 ))
471+ if gasTipCap .Cmp (doubledTipCap ) < 0 || gasFeeCap .Cmp (doubledFeeCap ) < 0 || blobGasFeeCap .Cmp (doubledBlobFeeCap ) < 0 {
472+ 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 )
473+ return nil , errors .New ("gas fees must be at least double" )
474+ }
475+
461476 feeData .gasFeeCap = gasFeeCap
462477 feeData .gasTipCap = gasTipCap
463478 feeData .blobGasFeeCap = blobGasFeeCap
@@ -520,7 +535,7 @@ func (s *Sender) checkPendingTransaction() {
520535 if receipt .BlockNumber .Uint64 () <= confirmed {
521536 if dbTxErr := s .db .Transaction (func (dbTX * gorm.DB ) error {
522537 // Update the status of the transaction to TxStatusConfirmed.
523- if updateErr := s .pendingTransactionOrm .UpdatePendingTransactionStatusByTxHash (s .ctx , originalTx .Hash (), types .TxStatusConfirmed , dbTX ); updateErr != nil {
538+ if updateErr := s .pendingTransactionOrm .UpdateTransactionStatusByTxHash (s .ctx , originalTx .Hash (), types .TxStatusConfirmed , dbTX ); updateErr != nil {
524539 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 )
525540 return updateErr
526541 }
@@ -595,7 +610,7 @@ func (s *Sender) checkPendingTransaction() {
595610 // 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.
596611 // This case will be handled by the checkPendingTransaction function.
597612 if dbTxErr := s .db .Transaction (func (dbTX * gorm.DB ) error {
598- if updateErr := s .pendingTransactionOrm .UpdatePendingTransactionStatusByTxHash (s .ctx , originalTx .Hash (), types .TxStatusReplaced , dbTX ); updateErr != nil {
613+ if updateErr := s .pendingTransactionOrm .UpdateTransactionStatusByTxHash (s .ctx , originalTx .Hash (), types .TxStatusReplaced , dbTX ); updateErr != nil {
599614 return fmt .Errorf ("failed to update status of transaction with hash %s to TxStatusReplaced, err: %w" , newSignedTx .Hash ().String (), updateErr )
600615 }
601616 if updateErr := s .pendingTransactionOrm .InsertPendingTransaction (s .ctx , txnToCheck .ContextID , s .getSenderMeta (), newSignedTx , blockNumber , dbTX ); updateErr != nil {
@@ -608,6 +623,23 @@ func (s *Sender) checkPendingTransaction() {
608623 }
609624
610625 if err := s .client .SendTransaction (s .ctx , newSignedTx ); err != nil {
626+ // SendTransaction failed, need to rollback the previous database changes
627+ if rollbackErr := s .db .Transaction (func (tx * gorm.DB ) error {
628+ // Restore original transaction status back to pending
629+ if updateErr := s .pendingTransactionOrm .UpdateTransactionStatusByTxHash (s .ctx , originalTx .Hash (), types .TxStatusPending , tx ); updateErr != nil {
630+ return fmt .Errorf ("failed to rollback status of original transaction, err: %w" , updateErr )
631+ }
632+ // Delete the new transaction that was inserted
633+ if updateErr := s .pendingTransactionOrm .DeleteTransactionByTxHash (s .ctx , newSignedTx .Hash (), tx ); updateErr != nil {
634+ return fmt .Errorf ("failed to delete new transaction, err: %w" , updateErr )
635+ }
636+ return nil
637+ }); rollbackErr != nil {
638+ // Both SendTransaction and rollback failed
639+ 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 )
640+ return
641+ }
642+
611643 log .Error ("failed to send replacing tx" , "tx hash" , newSignedTx .Hash ().String (), "from" , s .transactionSigner .GetAddr ().String (), "nonce" , newSignedTx .Nonce (), "err" , err )
612644 return
613645 }
0 commit comments