diff --git a/common/version/version.go b/common/version/version.go index 3c3cb0c350..0da2b3ef68 100644 --- a/common/version/version.go +++ b/common/version/version.go @@ -5,7 +5,7 @@ import ( "runtime/debug" ) -var tag = "v4.3.60" +var tag = "v4.3.61" var commit = func() string { if info, ok := debug.ReadBuildInfo(); ok { diff --git a/rollup/cmd/gas_oracle/app/app.go b/rollup/cmd/gas_oracle/app/app.go index 7cdcf9d95c..4de75b5686 100644 --- a/rollup/cmd/gas_oracle/app/app.go +++ b/rollup/cmd/gas_oracle/app/app.go @@ -79,11 +79,11 @@ func action(ctx *cli.Context) error { l1watcher := watcher.NewL1WatcherClient(ctx.Context, l1client, cfg.L1Config.StartHeight, cfg.L1Config.Confirmations, cfg.L1Config.L1MessageQueueAddress, cfg.L1Config.ScrollChainContractAddress, db, registry) - l1relayer, err := relayer.NewLayer1Relayer(ctx.Context, db, cfg.L1Config.RelayerConfig, registry) + l1relayer, err := relayer.NewLayer1Relayer(ctx.Context, db, cfg.L1Config.RelayerConfig, true, registry) if err != nil { log.Crit("failed to create new l1 relayer", "config file", cfgFile, "error", err) } - l2relayer, err := relayer.NewLayer2Relayer(ctx.Context, l2client, db, cfg.L2Config.RelayerConfig, false /* initGenesis */, registry) + l2relayer, err := relayer.NewLayer2Relayer(ctx.Context, l2client, db, cfg.L2Config.RelayerConfig, false /* initGenesis */, true, registry) if err != nil { log.Crit("failed to create new l2 relayer", "config file", cfgFile, "error", err) } diff --git a/rollup/cmd/rollup_relayer/app/app.go b/rollup/cmd/rollup_relayer/app/app.go index b33163927b..de8a9dd8a8 100644 --- a/rollup/cmd/rollup_relayer/app/app.go +++ b/rollup/cmd/rollup_relayer/app/app.go @@ -73,7 +73,7 @@ func action(ctx *cli.Context) error { } initGenesis := ctx.Bool(utils.ImportGenesisFlag.Name) - l2relayer, err := relayer.NewLayer2Relayer(ctx.Context, l2client, db, cfg.L2Config.RelayerConfig, initGenesis, registry) + l2relayer, err := relayer.NewLayer2Relayer(ctx.Context, l2client, db, cfg.L2Config.RelayerConfig, initGenesis, false, registry) if err != nil { log.Crit("failed to create l2 relayer", "config file", cfgFile, "error", err) } diff --git a/rollup/internal/controller/relayer/l1_relayer.go b/rollup/internal/controller/relayer/l1_relayer.go index fcc03eef80..be2b394812 100644 --- a/rollup/internal/controller/relayer/l1_relayer.go +++ b/rollup/internal/controller/relayer/l1_relayer.go @@ -42,8 +42,8 @@ type Layer1Relayer struct { } // NewLayer1Relayer will return a new instance of Layer1RelayerClient -func NewLayer1Relayer(ctx context.Context, db *gorm.DB, cfg *config.RelayerConfig, reg prometheus.Registerer) (*Layer1Relayer, error) { - gasOracleSender, err := sender.NewSender(ctx, cfg.SenderConfig, cfg.GasOracleSenderPrivateKey, "l1_relayer", "gas_oracle_sender", types.SenderTypeL1GasOracle, db, reg) +func NewLayer1Relayer(ctx context.Context, db *gorm.DB, cfg *config.RelayerConfig, gasOracle bool, reg prometheus.Registerer) (*Layer1Relayer, error) { + gasOracleSender, err := sender.NewSender(ctx, cfg.SenderConfig, cfg.GasOracleSenderPrivateKey, "l1_relayer", "gas_oracle_sender", types.SenderTypeL1GasOracle, db, gasOracle, reg) if err != nil { addr := crypto.PubkeyToAddress(cfg.GasOracleSenderPrivateKey.PublicKey) return nil, fmt.Errorf("new gas oracle sender failed for address %s, err: %v", addr.Hex(), err) diff --git a/rollup/internal/controller/relayer/l1_relayer_test.go b/rollup/internal/controller/relayer/l1_relayer_test.go index 6a0a3447c9..c570594736 100644 --- a/rollup/internal/controller/relayer/l1_relayer_test.go +++ b/rollup/internal/controller/relayer/l1_relayer_test.go @@ -35,7 +35,7 @@ func setupL1RelayerDB(t *testing.T) *gorm.DB { func testCreateNewL1Relayer(t *testing.T) { db := setupL1RelayerDB(t) defer database.CloseDB(db) - relayer, err := NewLayer1Relayer(context.Background(), db, cfg.L2Config.RelayerConfig, nil) + relayer, err := NewLayer1Relayer(context.Background(), db, cfg.L2Config.RelayerConfig, true, nil) assert.NoError(t, err) assert.NotNil(t, relayer) } @@ -56,7 +56,7 @@ func testL1RelayerGasOracleConfirm(t *testing.T) { l1Cfg := cfg.L1Config ctx, cancel := context.WithCancel(context.Background()) defer cancel() - l1Relayer, err := NewLayer1Relayer(ctx, db, l1Cfg.RelayerConfig, nil) + l1Relayer, err := NewLayer1Relayer(ctx, db, l1Cfg.RelayerConfig, true, nil) assert.NoError(t, err) // Simulate message confirmations. @@ -88,7 +88,7 @@ func testL1RelayerProcessGasPriceOracle(t *testing.T) { l1Cfg := cfg.L1Config ctx, cancel := context.WithCancel(context.Background()) defer cancel() - l1Relayer, err := NewLayer1Relayer(ctx, db, l1Cfg.RelayerConfig, nil) + l1Relayer, err := NewLayer1Relayer(ctx, db, l1Cfg.RelayerConfig, true, nil) assert.NoError(t, err) assert.NotNil(t, l1Relayer) diff --git a/rollup/internal/controller/relayer/l2_relayer.go b/rollup/internal/controller/relayer/l2_relayer.go index 46d7c0103d..a7d4d86835 100644 --- a/rollup/internal/controller/relayer/l2_relayer.go +++ b/rollup/internal/controller/relayer/l2_relayer.go @@ -62,19 +62,19 @@ type Layer2Relayer struct { } // NewLayer2Relayer will return a new instance of Layer2RelayerClient -func NewLayer2Relayer(ctx context.Context, l2Client *ethclient.Client, db *gorm.DB, cfg *config.RelayerConfig, initGenesis bool, reg prometheus.Registerer) (*Layer2Relayer, error) { - commitSender, err := sender.NewSender(ctx, cfg.SenderConfig, cfg.CommitSenderPrivateKey, "l2_relayer", "commit_sender", types.SenderTypeCommitBatch, db, reg) +func NewLayer2Relayer(ctx context.Context, l2Client *ethclient.Client, db *gorm.DB, cfg *config.RelayerConfig, initGenesis bool, gasOracle bool, reg prometheus.Registerer) (*Layer2Relayer, error) { + commitSender, err := sender.NewSender(ctx, cfg.SenderConfig, cfg.CommitSenderPrivateKey, "l2_relayer", "commit_sender", types.SenderTypeCommitBatch, db, !gasOracle, reg) if err != nil { addr := crypto.PubkeyToAddress(cfg.CommitSenderPrivateKey.PublicKey) return nil, fmt.Errorf("new commit sender failed for address %s, err: %w", addr.Hex(), err) } - finalizeSender, err := sender.NewSender(ctx, cfg.SenderConfig, cfg.FinalizeSenderPrivateKey, "l2_relayer", "finalize_sender", types.SenderTypeFinalizeBatch, db, reg) + finalizeSender, err := sender.NewSender(ctx, cfg.SenderConfig, cfg.FinalizeSenderPrivateKey, "l2_relayer", "finalize_sender", types.SenderTypeFinalizeBatch, db, !gasOracle, reg) if err != nil { addr := crypto.PubkeyToAddress(cfg.FinalizeSenderPrivateKey.PublicKey) return nil, fmt.Errorf("new finalize sender failed for address %s, err: %w", addr.Hex(), err) } - gasOracleSender, err := sender.NewSender(ctx, cfg.SenderConfig, cfg.GasOracleSenderPrivateKey, "l2_relayer", "gas_oracle_sender", types.SenderTypeL2GasOracle, db, reg) + gasOracleSender, err := sender.NewSender(ctx, cfg.SenderConfig, cfg.GasOracleSenderPrivateKey, "l2_relayer", "gas_oracle_sender", types.SenderTypeL2GasOracle, db, gasOracle, reg) if err != nil { addr := crypto.PubkeyToAddress(cfg.GasOracleSenderPrivateKey.PublicKey) return nil, fmt.Errorf("new gas oracle sender failed for address %s, err: %w", addr.Hex(), err) diff --git a/rollup/internal/controller/relayer/l2_relayer_test.go b/rollup/internal/controller/relayer/l2_relayer_test.go index de9f282450..84227440e5 100644 --- a/rollup/internal/controller/relayer/l2_relayer_test.go +++ b/rollup/internal/controller/relayer/l2_relayer_test.go @@ -38,7 +38,7 @@ func setupL2RelayerDB(t *testing.T) *gorm.DB { func testCreateNewRelayer(t *testing.T) { db := setupL2RelayerDB(t) defer database.CloseDB(db) - relayer, err := NewLayer2Relayer(context.Background(), l2Cli, db, cfg.L2Config.RelayerConfig, false, nil) + relayer, err := NewLayer2Relayer(context.Background(), l2Cli, db, cfg.L2Config.RelayerConfig, false, false, nil) assert.NoError(t, err) assert.NotNil(t, relayer) } @@ -48,7 +48,7 @@ func testL2RelayerProcessPendingBatches(t *testing.T) { defer database.CloseDB(db) l2Cfg := cfg.L2Config - relayer, err := NewLayer2Relayer(context.Background(), l2Cli, db, l2Cfg.RelayerConfig, false, nil) + relayer, err := NewLayer2Relayer(context.Background(), l2Cli, db, l2Cfg.RelayerConfig, false, false, nil) assert.NoError(t, err) l2BlockOrm := orm.NewL2Block(db) @@ -82,7 +82,7 @@ func testL2RelayerProcessCommittedBatches(t *testing.T) { defer database.CloseDB(db) l2Cfg := cfg.L2Config - relayer, err := NewLayer2Relayer(context.Background(), l2Cli, db, l2Cfg.RelayerConfig, false, nil) + relayer, err := NewLayer2Relayer(context.Background(), l2Cli, db, l2Cfg.RelayerConfig, false, false, nil) assert.NoError(t, err) batchMeta := &types.BatchMeta{ StartChunkIndex: 0, @@ -128,7 +128,7 @@ func testL2RelayerFinalizeTimeoutBatches(t *testing.T) { l2Cfg := cfg.L2Config l2Cfg.RelayerConfig.EnableTestEnvBypassFeatures = true l2Cfg.RelayerConfig.FinalizeBatchWithoutProofTimeoutSec = 0 - relayer, err := NewLayer2Relayer(context.Background(), l2Cli, db, l2Cfg.RelayerConfig, false, nil) + relayer, err := NewLayer2Relayer(context.Background(), l2Cli, db, l2Cfg.RelayerConfig, false, false, nil) assert.NoError(t, err) batchMeta := &types.BatchMeta{ StartChunkIndex: 0, @@ -160,7 +160,7 @@ func testL2RelayerCommitConfirm(t *testing.T) { l2Cfg := cfg.L2Config ctx, cancel := context.WithCancel(context.Background()) defer cancel() - l2Relayer, err := NewLayer2Relayer(ctx, l2Cli, db, l2Cfg.RelayerConfig, false, nil) + l2Relayer, err := NewLayer2Relayer(ctx, l2Cli, db, l2Cfg.RelayerConfig, false, false, nil) assert.NoError(t, err) // Simulate message confirmations. @@ -214,7 +214,7 @@ func testL2RelayerFinalizeConfirm(t *testing.T) { l2Cfg := cfg.L2Config ctx, cancel := context.WithCancel(context.Background()) defer cancel() - l2Relayer, err := NewLayer2Relayer(ctx, l2Cli, db, l2Cfg.RelayerConfig, false, nil) + l2Relayer, err := NewLayer2Relayer(ctx, l2Cli, db, l2Cfg.RelayerConfig, false, false, nil) assert.NoError(t, err) // Simulate message confirmations. @@ -287,7 +287,7 @@ func testL2RelayerGasOracleConfirm(t *testing.T) { l2Cfg := cfg.L2Config ctx, cancel := context.WithCancel(context.Background()) defer cancel() - l2Relayer, err := NewLayer2Relayer(ctx, l2Cli, db, l2Cfg.RelayerConfig, false, nil) + l2Relayer, err := NewLayer2Relayer(ctx, l2Cli, db, l2Cfg.RelayerConfig, false, false, nil) assert.NoError(t, err) // Simulate message confirmations. @@ -326,7 +326,7 @@ func testLayer2RelayerProcessGasPriceOracle(t *testing.T) { db := setupL2RelayerDB(t) defer database.CloseDB(db) - relayer, err := NewLayer2Relayer(context.Background(), l2Cli, db, cfg.L2Config.RelayerConfig, false, nil) + relayer, err := NewLayer2Relayer(context.Background(), l2Cli, db, cfg.L2Config.RelayerConfig, false, true, nil) assert.NoError(t, err) assert.NotNil(t, relayer) @@ -439,7 +439,7 @@ func testGetBatchStatusByIndex(t *testing.T) { assert.NoError(t, err) cfg.L2Config.RelayerConfig.ChainMonitor.Enabled = true - relayer, err := NewLayer2Relayer(context.Background(), l2Cli, db, cfg.L2Config.RelayerConfig, false, nil) + relayer, err := NewLayer2Relayer(context.Background(), l2Cli, db, cfg.L2Config.RelayerConfig, false, false, nil) assert.NoError(t, err) assert.NotNil(t, relayer) diff --git a/rollup/internal/controller/sender/sender.go b/rollup/internal/controller/sender/sender.go index b48bf1ecce..2af60dc5b7 100644 --- a/rollup/internal/controller/sender/sender.go +++ b/rollup/internal/controller/sender/sender.go @@ -81,7 +81,7 @@ type Sender struct { } // NewSender returns a new instance of transaction sender -func NewSender(ctx context.Context, config *config.SenderConfig, priv *ecdsa.PrivateKey, service, name string, senderType types.SenderType, db *gorm.DB, reg prometheus.Registerer) (*Sender, error) { +func NewSender(ctx context.Context, config *config.SenderConfig, priv *ecdsa.PrivateKey, service, name string, senderType types.SenderType, db *gorm.DB, enableSender bool, reg prometheus.Registerer) (*Sender, error) { if config.EscalateMultipleNum <= config.EscalateMultipleDen { return nil, fmt.Errorf("invalid params, EscalateMultipleNum; %v, EscalateMultipleDen: %v", config.EscalateMultipleNum, config.EscalateMultipleDen) } @@ -126,7 +126,9 @@ func NewSender(ctx context.Context, config *config.SenderConfig, priv *ecdsa.Pri } sender.metrics = initSenderMetrics(reg) - go sender.loop(ctx) + if enableSender { + go sender.loop(ctx) + } return sender, nil } @@ -298,7 +300,7 @@ func (s *Sender) resetNonce(ctx context.Context) { s.auth.Nonce = big.NewInt(int64(nonce)) } -func (s *Sender) resubmitTransaction(auth *bind.TransactOpts, tx *gethTypes.Transaction, baseFee uint64) (*gethTypes.Transaction, error) { +func (s *Sender) resubmitTransaction(tx *gethTypes.Transaction, baseFee uint64) (*gethTypes.Transaction, error) { escalateMultipleNum := new(big.Int).SetUint64(s.config.EscalateMultipleNum) escalateMultipleDen := new(big.Int).SetUint64(s.config.EscalateMultipleDen) maxGasPrice := new(big.Int).SetUint64(s.config.MaxGasPrice) @@ -306,7 +308,7 @@ func (s *Sender) resubmitTransaction(auth *bind.TransactOpts, tx *gethTypes.Tran txInfo := map[string]interface{}{ "tx_hash": tx.Hash().String(), "tx_type": s.config.TxType, - "from": auth.From.String(), + "from": s.auth.From.String(), "nonce": tx.Nonce(), } @@ -375,7 +377,7 @@ func (s *Sender) resubmitTransaction(auth *bind.TransactOpts, tx *gethTypes.Tran txInfo["adjusted_gas_fee_cap"] = gasFeeCap.Uint64() } - log.Info("Transaction gas adjustment details", "txInfo", txInfo) + log.Info("Transaction gas adjustment details", "service", s.service, "name", s.name, "txInfo", txInfo) nonce := tx.Nonce() s.metrics.resubmitTransactionTotal.WithLabelValues(s.service, s.name).Inc() @@ -434,7 +436,8 @@ func (s *Sender) checkPendingTransaction() { return nil }) if err != nil { - log.Error("db transaction failed", "err", err) + log.Error("db transaction failed after receiving confirmation", "err", err) + return } // send confirm message @@ -456,10 +459,12 @@ func (s *Sender) checkPendingTransaction() { } if status == types.TxStatusConfirmedFailed { log.Warn("transaction already marked as failed, skipping resubmission", "hash", tx.Hash().String()) - return + continue } log.Info("resubmit transaction", + "service", s.service, + "name", s.name, "hash", tx.Hash().String(), "from", s.auth.From.String(), "nonce", tx.Nonce(), @@ -467,7 +472,7 @@ func (s *Sender) checkPendingTransaction() { "currentBlockNumber", blockNumber, "escalateBlocks", s.config.EscalateBlocks) - if newTx, err := s.resubmitTransaction(s.auth, tx, baseFee); err != nil { + if newTx, err := s.resubmitTransaction(tx, baseFee); err != nil { s.metrics.resubmitTransactionFailedTotal.WithLabelValues(s.service, s.name).Inc() log.Error("failed to resubmit transaction", "context ID", txnToCheck.ContextID, "sender meta", s.getSenderMeta(), "from", s.auth.From.String(), "nonce", newTx.Nonce(), "err", err) } else { @@ -477,13 +482,14 @@ func (s *Sender) checkPendingTransaction() { return fmt.Errorf("failed to update status of transaction with hash %s to TxStatusReplaced, err: %w", tx.Hash().String(), err) } // Record the new transaction that has replaced the original one. - if err := s.pendingTransactionOrm.InsertPendingTransaction(s.ctx, txnToCheck.ContextID, s.getSenderMeta(), newTx, txnToCheck.SubmitBlockNumber, dbTX); err != nil { - return fmt.Errorf("failed to insert new pending transaction with context ID: %s, nonce: %d, hash: %v, err: %w", txnToCheck.ContextID, newTx.Nonce(), newTx.Hash().String(), err) + if err := s.pendingTransactionOrm.InsertPendingTransaction(s.ctx, txnToCheck.ContextID, s.getSenderMeta(), newTx, blockNumber, dbTX); err != nil { + return fmt.Errorf("failed to insert new pending transaction with context ID: %s, nonce: %d, hash: %v, previous block number: %v, current block number: %v, err: %w", txnToCheck.ContextID, newTx.Nonce(), newTx.Hash().String(), txnToCheck.SubmitBlockNumber, blockNumber, err) } return nil }) if err != nil { - log.Error("db transaction failed", "err", err) + log.Error("db transaction failed after resubmitting", "err", err) + return } } } diff --git a/rollup/internal/controller/sender/sender_test.go b/rollup/internal/controller/sender/sender_test.go index aeda8cce26..adf8496ca9 100644 --- a/rollup/internal/controller/sender/sender_test.go +++ b/rollup/internal/controller/sender/sender_test.go @@ -106,6 +106,7 @@ func TestSender(t *testing.T) { 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) + t.Run("test check pending transaction multiple times with only one transaction pending", testCheckPendingTransactionTxMultipleTimesWithOnlyOneTxPending) } func testNewSender(t *testing.T) { @@ -117,7 +118,7 @@ func testNewSender(t *testing.T) { // exit by Stop() cfgCopy1 := *cfg.L1Config.RelayerConfig.SenderConfig cfgCopy1.TxType = txType - newSender1, err := NewSender(context.Background(), &cfgCopy1, privateKey, "test", "test", types.SenderTypeUnknown, db, nil) + newSender1, err := NewSender(context.Background(), &cfgCopy1, privateKey, "test", "test", types.SenderTypeUnknown, db, true, nil) assert.NoError(t, err) newSender1.Stop() @@ -125,7 +126,7 @@ func testNewSender(t *testing.T) { cfgCopy2 := *cfg.L1Config.RelayerConfig.SenderConfig cfgCopy2.TxType = txType subCtx, cancel := context.WithCancel(context.Background()) - _, err = NewSender(subCtx, &cfgCopy2, privateKey, "test", "test", types.SenderTypeUnknown, db, nil) + _, err = NewSender(subCtx, &cfgCopy2, privateKey, "test", "test", types.SenderTypeUnknown, db, true, nil) assert.NoError(t, err) cancel() } @@ -139,7 +140,7 @@ func testSendAndRetrieveTransaction(t *testing.T) { cfgCopy := *cfg.L1Config.RelayerConfig.SenderConfig cfgCopy.TxType = txType - s, err := NewSender(context.Background(), &cfgCopy, privateKey, "test", "test", types.SenderTypeUnknown, db, nil) + s, err := NewSender(context.Background(), &cfgCopy, privateKey, "test", "test", types.SenderTypeUnknown, db, true, nil) assert.NoError(t, err) hash, err := s.SendTransaction("0", &common.Address{}, big.NewInt(0), nil, 0) @@ -168,7 +169,7 @@ func testFallbackGasLimit(t *testing.T) { cfgCopy := *cfg.L1Config.RelayerConfig.SenderConfig cfgCopy.TxType = txType cfgCopy.Confirmations = rpc.LatestBlockNumber - s, err := NewSender(context.Background(), &cfgCopy, privateKey, "test", "test", types.SenderTypeUnknown, db, nil) + s, err := NewSender(context.Background(), &cfgCopy, privateKey, "test", "test", types.SenderTypeUnknown, db, true, nil) assert.NoError(t, err) client, err := ethclient.Dial(cfgCopy.Endpoint) @@ -207,7 +208,7 @@ func testResubmitZeroGasPriceTransaction(t *testing.T) { cfgCopy := *cfg.L1Config.RelayerConfig.SenderConfig cfgCopy.TxType = txType - s, err := NewSender(context.Background(), &cfgCopy, privateKey, "test", "test", types.SenderTypeUnknown, db, nil) + s, err := NewSender(context.Background(), &cfgCopy, privateKey, "test", "test", types.SenderTypeUnknown, db, true, nil) assert.NoError(t, err) feeData := &FeeData{ gasPrice: big.NewInt(0), @@ -219,7 +220,7 @@ func testResubmitZeroGasPriceTransaction(t *testing.T) { assert.NoError(t, err) assert.NotNil(t, tx) // Increase at least 1 wei in gas price, gas tip cap and gas fee cap. - _, err = s.resubmitTransaction(s.auth, tx, 0) + _, err = s.resubmitTransaction(tx, 0) assert.NoError(t, err) s.Stop() } @@ -233,7 +234,7 @@ func testAccessListTransactionGasLimit(t *testing.T) { cfgCopy := *cfg.L1Config.RelayerConfig.SenderConfig cfgCopy.TxType = txType - s, err := NewSender(context.Background(), &cfgCopy, privateKey, "test", "test", types.SenderTypeUnknown, db, nil) + s, err := NewSender(context.Background(), &cfgCopy, privateKey, "test", "test", types.SenderTypeUnknown, db, true, nil) assert.NoError(t, err) l2GasOracleABI, err := bridgeAbi.L2GasPriceOracleMetaData.GetAbi() @@ -267,7 +268,7 @@ func testResubmitNonZeroGasPriceTransaction(t *testing.T) { cfgCopy.EscalateMultipleNum = 110 cfgCopy.EscalateMultipleDen = 100 cfgCopy.TxType = txType - s, err := NewSender(context.Background(), &cfgCopy, privateKey, "test", "test", types.SenderTypeUnknown, db, nil) + s, err := NewSender(context.Background(), &cfgCopy, privateKey, "test", "test", types.SenderTypeUnknown, db, true, nil) assert.NoError(t, err) feeData := &FeeData{ gasPrice: big.NewInt(100000), @@ -278,7 +279,7 @@ func testResubmitNonZeroGasPriceTransaction(t *testing.T) { tx, err := s.createAndSendTx(feeData, &common.Address{}, big.NewInt(0), nil, nil) assert.NoError(t, err) assert.NotNil(t, tx) - _, err = s.resubmitTransaction(s.auth, tx, 0) + _, err = s.resubmitTransaction(tx, 0) assert.NoError(t, err) s.Stop() } @@ -295,7 +296,7 @@ func testResubmitUnderpricedTransaction(t *testing.T) { cfgCopy.EscalateMultipleNum = 109 cfgCopy.EscalateMultipleDen = 100 cfgCopy.TxType = txType - s, err := NewSender(context.Background(), &cfgCopy, privateKey, "test", "test", types.SenderTypeUnknown, db, nil) + s, err := NewSender(context.Background(), &cfgCopy, privateKey, "test", "test", types.SenderTypeUnknown, db, true, nil) assert.NoError(t, err) feeData := &FeeData{ gasPrice: big.NewInt(100000), @@ -306,7 +307,7 @@ func testResubmitUnderpricedTransaction(t *testing.T) { tx, err := s.createAndSendTx(feeData, &common.Address{}, big.NewInt(0), nil, nil) assert.NoError(t, err) assert.NotNil(t, tx) - _, err = s.resubmitTransaction(s.auth, tx, 0) + _, err = s.resubmitTransaction(tx, 0) assert.Error(t, err, "replacement transaction underpriced") s.Stop() } @@ -321,14 +322,14 @@ func testResubmitTransactionWithRisingBaseFee(t *testing.T) { cfgCopy := *cfg.L1Config.RelayerConfig.SenderConfig cfgCopy.TxType = txType - s, err := NewSender(context.Background(), &cfgCopy, privateKey, "test", "test", types.SenderTypeUnknown, db, nil) + s, err := NewSender(context.Background(), &cfgCopy, privateKey, "test", "test", types.SenderTypeUnknown, db, true, nil) assert.NoError(t, err) tx := gethTypes.NewTransaction(s.auth.Nonce.Uint64(), common.Address{}, big.NewInt(0), 21000, big.NewInt(0), nil) baseFeePerGas := uint64(1000) // bump the basefee by 10x baseFeePerGas *= 10 // resubmit and check that the gas fee has been adjusted accordingly - newTx, err := s.resubmitTransaction(s.auth, tx, baseFeePerGas) + newTx, err := s.resubmitTransaction(tx, baseFeePerGas) assert.NoError(t, err) escalateMultipleNum := new(big.Int).SetUint64(s.config.EscalateMultipleNum) @@ -357,7 +358,7 @@ func testCheckPendingTransactionTxConfirmed(t *testing.T) { cfgCopy := *cfg.L1Config.RelayerConfig.SenderConfig cfgCopy.TxType = txType - s, err := NewSender(context.Background(), &cfgCopy, privateKey, "test", "test", types.SenderTypeCommitBatch, db, nil) + s, err := NewSender(context.Background(), &cfgCopy, privateKey, "test", "test", types.SenderTypeCommitBatch, db, true, nil) assert.NoError(t, err) _, err = s.SendTransaction("test", &common.Address{}, big.NewInt(0), nil, 0) @@ -394,7 +395,7 @@ func testCheckPendingTransactionResubmitTxConfirmed(t *testing.T) { cfgCopy := *cfg.L1Config.RelayerConfig.SenderConfig cfgCopy.TxType = txType cfgCopy.EscalateBlocks = 0 - s, err := NewSender(context.Background(), &cfgCopy, privateKey, "test", "test", types.SenderTypeFinalizeBatch, db, nil) + s, err := NewSender(context.Background(), &cfgCopy, privateKey, "test", "test", types.SenderTypeFinalizeBatch, db, true, nil) assert.NoError(t, err) originTxHash, err := s.SendTransaction("test", &common.Address{}, big.NewInt(0), nil, 0) @@ -449,7 +450,7 @@ func testCheckPendingTransactionReplacedTxConfirmed(t *testing.T) { cfgCopy := *cfg.L1Config.RelayerConfig.SenderConfig cfgCopy.TxType = txType cfgCopy.EscalateBlocks = 0 - s, err := NewSender(context.Background(), &cfgCopy, privateKey, "test", "test", types.SenderTypeL1GasOracle, db, nil) + s, err := NewSender(context.Background(), &cfgCopy, privateKey, "test", "test", types.SenderTypeL1GasOracle, db, true, nil) assert.NoError(t, err) txHash, err := s.SendTransaction("test", &common.Address{}, big.NewInt(0), nil, 0) @@ -504,3 +505,46 @@ func testCheckPendingTransactionReplacedTxConfirmed(t *testing.T) { patchGuard.Reset() } } + +func testCheckPendingTransactionTxMultipleTimesWithOnlyOneTxPending(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.SenderTypeCommitBatch, db, true, nil) + assert.NoError(t, err) + + _, err = s.SendTransaction("test", &common.Address{}, big.NewInt(0), 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) + assert.Equal(t, types.TxStatusPending, txs[0].Status) + assert.Equal(t, types.SenderTypeCommitBatch, txs[0].SenderType) + + patchGuard := gomonkey.ApplyMethodFunc(s.client, "TransactionReceipt", func(_ context.Context, hash common.Hash) (*gethTypes.Receipt, error) { + return nil, fmt.Errorf("simulated transaction receipt error") + }) + + for i := 1; i <= 6; i++ { + s.checkPendingTransaction() + assert.NoError(t, err) + + txs, err = s.pendingTransactionOrm.GetPendingOrReplacedTransactionsBySenderType(context.Background(), s.senderType, 100) + assert.NoError(t, err) + assert.Len(t, txs, i+1) + for j := 0; j < i; j++ { + assert.Equal(t, types.TxStatusReplaced, txs[j].Status) + } + assert.Equal(t, types.TxStatusPending, txs[i].Status) + } + + s.Stop() + patchGuard.Reset() + } +} diff --git a/rollup/internal/controller/watcher/l2_watcher_test.go b/rollup/internal/controller/watcher/l2_watcher_test.go index ecdbb4465a..134ec902c8 100644 --- a/rollup/internal/controller/watcher/l2_watcher_test.go +++ b/rollup/internal/controller/watcher/l2_watcher_test.go @@ -52,7 +52,7 @@ func testCreateNewWatcherAndStop(t *testing.T) { l1cfg := cfg.L1Config l1cfg.RelayerConfig.SenderConfig.Confirmations = rpc.LatestBlockNumber - newSender, err := sender.NewSender(context.Background(), l1cfg.RelayerConfig.SenderConfig, l1cfg.RelayerConfig.GasOracleSenderPrivateKey, "test", "test", types.SenderTypeUnknown, db, nil) + newSender, err := sender.NewSender(context.Background(), l1cfg.RelayerConfig.SenderConfig, l1cfg.RelayerConfig.GasOracleSenderPrivateKey, "test", "test", types.SenderTypeUnknown, db, true, nil) assert.NoError(t, err) // Create several transactions and commit to block diff --git a/rollup/tests/gas_oracle_test.go b/rollup/tests/gas_oracle_test.go index 176b57cab8..7568d78d05 100644 --- a/rollup/tests/gas_oracle_test.go +++ b/rollup/tests/gas_oracle_test.go @@ -26,7 +26,7 @@ func testImportL1GasPrice(t *testing.T) { l1Cfg := rollupApp.Config.L1Config // Create L1Relayer - l1Relayer, err := relayer.NewLayer1Relayer(context.Background(), db, l1Cfg.RelayerConfig, nil) + l1Relayer, err := relayer.NewLayer1Relayer(context.Background(), db, l1Cfg.RelayerConfig, true, nil) assert.NoError(t, err) // Create L1Watcher @@ -67,7 +67,7 @@ func testImportL2GasPrice(t *testing.T) { prepareContracts(t) l2Cfg := rollupApp.Config.L2Config - l2Relayer, err := relayer.NewLayer2Relayer(context.Background(), l2Client, db, l2Cfg.RelayerConfig, false, nil) + l2Relayer, err := relayer.NewLayer2Relayer(context.Background(), l2Client, db, l2Cfg.RelayerConfig, false, true, nil) assert.NoError(t, err) // add fake chunk diff --git a/rollup/tests/rollup_test.go b/rollup/tests/rollup_test.go index 682b2dfe68..07f01e4728 100644 --- a/rollup/tests/rollup_test.go +++ b/rollup/tests/rollup_test.go @@ -27,7 +27,7 @@ func testCommitAndFinalizeGenesisBatch(t *testing.T) { prepareContracts(t) l2Cfg := rollupApp.Config.L2Config - l2Relayer, err := relayer.NewLayer2Relayer(context.Background(), l2Client, db, l2Cfg.RelayerConfig, true, nil) + l2Relayer, err := relayer.NewLayer2Relayer(context.Background(), l2Client, db, l2Cfg.RelayerConfig, true, false, nil) assert.NoError(t, err) assert.NotNil(t, l2Relayer) @@ -56,7 +56,7 @@ func testCommitBatchAndFinalizeBatch(t *testing.T) { // Create L2Relayer l2Cfg := rollupApp.Config.L2Config - l2Relayer, err := relayer.NewLayer2Relayer(context.Background(), l2Client, db, l2Cfg.RelayerConfig, false, nil) + l2Relayer, err := relayer.NewLayer2Relayer(context.Background(), l2Client, db, l2Cfg.RelayerConfig, false, false, nil) assert.NoError(t, err) // Create L1Watcher