Skip to content

Commit

Permalink
add unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
colinlyguo committed Jan 17, 2024
1 parent 7b0495c commit 1dd1d64
Show file tree
Hide file tree
Showing 2 changed files with 137 additions and 4 deletions.
5 changes: 2 additions & 3 deletions rollup/internal/controller/sender/sender.go
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,7 @@ func (s *Sender) checkPendingTransaction() {

confirmed, err := utils.GetLatestConfirmedBlockNumber(s.ctx, s.client, s.config.Confirmations)
if err != nil {
log.Error("failed to get latest confirmed block number", "err", err)
log.Error("failed to get latest confirmed block number", "confirmations", s.config.Confirmations, "err", err)
return
}

Expand All @@ -427,7 +427,6 @@ func (s *Sender) checkPendingTransaction() {
log.Error("failed to update other transactions as failed by nonce", "senderAddress", txnToCheck.SenderAddress, "nonce", txnToCheck.Nonce, "excludedTxHash", txnToCheck.Hash, "err", err)
return err
}

return nil
})
if err != nil {
Expand All @@ -443,7 +442,7 @@ func (s *Sender) checkPendingTransaction() {
}
}
} else if txnToCheck.Status == types.TxStatusPending && // Only resubmit the last pending transaction of the same ContextID.
s.config.EscalateBlocks+txnToCheck.SubmitBlockNumber < blockNumber {
s.config.EscalateBlocks+txnToCheck.SubmitBlockNumber <= blockNumber {
// It's possible that the pending transaction was marked as failed earlier in this loop (e.g., if one of its replacements has already been confirmed).
// Therefore, we fetch the current transaction status again for accuracy before proceeding.
status, err := s.pendingTransactionOrm.GetTxStatusByTxHash(s.ctx, tx.Hash().String())
Expand Down
136 changes: 135 additions & 1 deletion rollup/internal/controller/sender/sender_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"crypto/ecdsa"
"errors"
"fmt"
"math/big"
"testing"

Expand Down Expand Up @@ -81,6 +82,9 @@ func TestSender(t *testing.T) {
t.Run("test resubmit non-zero gas price transaction", testResubmitNonZeroGasPriceTransaction)
t.Run("test resubmit under priced transaction", testResubmitUnderpricedTransaction)
t.Run("test resubmit transaction with rising base fee", testResubmitTransactionWithRisingBaseFee)
t.Run("test check pending transaction tx confirmed", testCheckPendingTransactionTxConfirmed)
t.Run("test check pending transaction resubmit tx confirmed", testCheckPendingTransactionResubmitTxConfirmed)
t.Run("test check pending transaction replaced tx confirmed", testCheckPendingTransactionReplacedTxConfirmed)
}

func testNewSender(t *testing.T) {
Expand Down Expand Up @@ -116,7 +120,6 @@ func testSendAndRetrieveTransaction(t *testing.T) {
cfgCopy1.TxType = txType
s, err := NewSender(context.Background(), &cfgCopy1, privateKey, "test", "test", types.SenderTypeUnknown, db, nil)
assert.NoError(t, err)
defer s.Stop()

hash, err := s.SendTransaction("0", &common.Address{}, big.NewInt(1), nil, 0)
assert.NoError(t, err)
Expand All @@ -131,6 +134,7 @@ func testSendAndRetrieveTransaction(t *testing.T) {
assert.Equal(t, types.SenderTypeUnknown, txs[0].SenderType)
assert.Equal(t, "test", txs[0].SenderService)
assert.Equal(t, "test", txs[0].SenderName)
s.Stop()
}
}

Expand Down Expand Up @@ -291,3 +295,133 @@ func testResubmitTransactionWithRisingBaseFee(t *testing.T) {
assert.Equal(t, expectedGasFeeCap.Int64(), newTx.GasFeeCap().Int64())
s.Stop()
}

func testCheckPendingTransactionTxConfirmed(t *testing.T) {
for _, txType := range txTypes {
sqlDB, err := db.DB()
assert.NoError(t, err)
assert.NoError(t, migrate.ResetDB(sqlDB))

cfgCopy := *cfg.L1Config.RelayerConfig.SenderConfig
cfgCopy.TxType = txType
s, err := NewSender(context.Background(), &cfgCopy, privateKey, "test", "test", types.SenderTypeUnknown, db, nil)
assert.NoError(t, err)

_, err = s.SendTransaction("test", &common.Address{}, big.NewInt(1), nil, 0)
assert.NoError(t, err)

txs, err := s.pendingTransactionOrm.GetPendingOrReplacedTransactionsBySenderType(context.Background(), s.senderType, 1)
assert.NoError(t, err)
assert.Len(t, txs, 1)

patchGuard := gomonkey.ApplyMethodFunc(s.client, "TransactionReceipt", func(_ context.Context, hash common.Hash) (*gethTypes.Receipt, error) {
return &gethTypes.Receipt{TxHash: hash, BlockNumber: big.NewInt(0), Status: gethTypes.ReceiptStatusSuccessful}, nil
})

s.checkPendingTransaction()
assert.NoError(t, err)

txs, err = s.pendingTransactionOrm.GetPendingOrReplacedTransactionsBySenderType(context.Background(), s.senderType, 1)
assert.NoError(t, err)
assert.Len(t, txs, 0)

s.Stop()
patchGuard.Reset()
}
}

func testCheckPendingTransactionResubmitTxConfirmed(t *testing.T) {
for _, txType := range txTypes {
sqlDB, err := db.DB()
assert.NoError(t, err)
assert.NoError(t, migrate.ResetDB(sqlDB))

cfgCopy := *cfg.L1Config.RelayerConfig.SenderConfig
cfgCopy.TxType = txType
cfgCopy.EscalateBlocks = 0
s, err := NewSender(context.Background(), &cfgCopy, privateKey, "test", "test", types.SenderTypeUnknown, db, nil)
assert.NoError(t, err)

originTxHash, err := s.SendTransaction("test", &common.Address{}, big.NewInt(1), nil, 0)
assert.NoError(t, err)

txs, err := s.pendingTransactionOrm.GetPendingOrReplacedTransactionsBySenderType(context.Background(), s.senderType, 1)
assert.NoError(t, err)
assert.Len(t, txs, 1)

patchGuard := gomonkey.ApplyMethodFunc(s.client, "TransactionReceipt", func(_ context.Context, hash common.Hash) (*gethTypes.Receipt, error) {
if hash == originTxHash {
return nil, fmt.Errorf("simulated transaction receipt error")
}
return &gethTypes.Receipt{TxHash: hash, BlockNumber: big.NewInt(0), Status: gethTypes.ReceiptStatusSuccessful}, nil
})

// Attempt to resubmit the transaction.
s.checkPendingTransaction()
assert.NoError(t, err)

// Check the pending transactions again after attempting to resubmit.
s.checkPendingTransaction()
assert.NoError(t, err)

txs, err = s.pendingTransactionOrm.GetPendingOrReplacedTransactionsBySenderType(context.Background(), s.senderType, 1)
assert.NoError(t, err)
assert.Len(t, txs, 0)

s.Stop()
patchGuard.Reset()
}
}

func testCheckPendingTransactionReplacedTxConfirmed(t *testing.T) {
for _, txType := range txTypes {
sqlDB, err := db.DB()
assert.NoError(t, err)
assert.NoError(t, migrate.ResetDB(sqlDB))

cfgCopy := *cfg.L1Config.RelayerConfig.SenderConfig
cfgCopy.TxType = txType
cfgCopy.EscalateBlocks = 0
s, err := NewSender(context.Background(), &cfgCopy, privateKey, "test", "test", types.SenderTypeUnknown, db, nil)
assert.NoError(t, err)

_, err = s.SendTransaction("test", &common.Address{}, big.NewInt(1), nil, 0)
assert.NoError(t, err)

txs, err := s.pendingTransactionOrm.GetPendingOrReplacedTransactionsBySenderType(context.Background(), s.senderType, 1)
assert.NoError(t, err)
assert.Len(t, txs, 1)

patchGuard := gomonkey.ApplyMethodFunc(s.client, "TransactionReceipt", func(_ context.Context, hash common.Hash) (*gethTypes.Receipt, error) {
var status types.TxStatus
status, err = s.pendingTransactionOrm.GetTxStatusByTxHash(context.Background(), hash.Hex())
if err != nil {
return nil, fmt.Errorf("failed to get transaction status, hash: %s, err: %w", hash.Hex(), err)
}
// If the transaction status is 'replaced', return a successful receipt.
if status == types.TxStatusReplaced {
return &gethTypes.Receipt{
TxHash: hash,
BlockNumber: big.NewInt(0),
Status: gethTypes.ReceiptStatusSuccessful,
}, nil
}
return nil, fmt.Errorf("simulated transaction receipt error")
})

// Attempt to resubmit the transaction.
s.checkPendingTransaction()
assert.NoError(t, err)

// Check the pending transactions again after attempting to resubmit.
s.checkPendingTransaction()
assert.NoError(t, err)

txs, err = s.pendingTransactionOrm.GetPendingOrReplacedTransactionsBySenderType(context.Background(), s.senderType, 1)
assert.NoError(t, err)
assert.Len(t, txs, 0)

s.Stop()
patchGuard.Reset()
}
}

0 comments on commit 1dd1d64

Please sign in to comment.