Skip to content

Commit 86b18d5

Browse files
author
colinlyguo
committed
address comments
1 parent 22a1108 commit 86b18d5

File tree

3 files changed

+67
-44
lines changed

3 files changed

+67
-44
lines changed

rollup/internal/controller/sender/sender.go

Lines changed: 48 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ type FeeData struct {
6363
gasLimit uint64
6464
}
6565

66-
// Sender Transaction sender to send transaction to l1/l2 geth
66+
// Sender Transaction sender to send transaction to l1/l2
6767
type Sender struct {
6868
config *config.SenderConfig
6969
gethClient *gethclient.Client
@@ -105,30 +105,7 @@ func NewSender(ctx context.Context, config *config.SenderConfig, signerConfig *c
105105
return nil, fmt.Errorf("failed to create transaction signer, err: %w", err)
106106
}
107107

108-
// Get maximum nonce from database
109-
dbNonce, err := orm.NewPendingTransaction(db).GetMaxNonceBySenderAddress(ctx, transactionSigner.GetAddr().Hex())
110-
if err != nil {
111-
return nil, fmt.Errorf("failed to get max nonce from database for address %s, err: %w", transactionSigner.GetAddr().Hex(), err)
112-
}
113-
114-
// Get pending nonce from the client
115-
pendingNonce, err := client.PendingNonceAt(ctx, transactionSigner.GetAddr())
116-
if err != nil {
117-
return nil, fmt.Errorf("failed to get pending nonce for address %s, err: %w", transactionSigner.GetAddr().Hex(), err)
118-
}
119-
120-
// Take the maximum of both values
121-
var finalNonce uint64
122-
if pendingNonce > dbNonce {
123-
finalNonce = pendingNonce
124-
} else {
125-
finalNonce = dbNonce
126-
}
127-
128-
log.Info("nonce initialization", "address", transactionSigner.GetAddr().Hex(), "pendingNonce", pendingNonce, "dbNonce", dbNonce, "finalNonce", finalNonce)
129-
130-
transactionSigner.SetNonce(finalNonce)
131-
108+
// Create sender instance first and then initialize nonce
132109
sender := &Sender{
133110
ctx: ctx,
134111
config: config,
@@ -144,8 +121,13 @@ func NewSender(ctx context.Context, config *config.SenderConfig, signerConfig *c
144121
service: service,
145122
senderType: senderType,
146123
}
147-
sender.metrics = initSenderMetrics(reg)
148124

125+
// Initialize nonce using the new method
126+
if err := sender.resetNonce(); err != nil {
127+
return nil, fmt.Errorf("failed to reset nonce: %w", err)
128+
}
129+
130+
sender.metrics = initSenderMetrics(reg)
149131
go sender.loop(ctx)
150132

151133
return sender, nil
@@ -259,7 +241,10 @@ func (s *Sender) SendTransaction(contextID string, target *common.Address, data
259241
// Check if contain nonce, and reset nonce
260242
// only reset nonce when it is not from resubmit
261243
if strings.Contains(err.Error(), "nonce too low") {
262-
s.resetNonce(context.Background())
244+
if err := s.resetNonce(); err != nil {
245+
log.Warn("failed to reset nonce after failed send transaction", "address", s.transactionSigner.GetAddr().String(), "err", err)
246+
return common.Hash{}, 0, fmt.Errorf("failed to reset nonce after failed send transaction, err: %w", err)
247+
}
263248
}
264249
return common.Hash{}, 0, fmt.Errorf("failed to send transaction, err: %w", err)
265250
}
@@ -344,14 +329,46 @@ func (s *Sender) createTx(feeData *FeeData, target *common.Address, data []byte,
344329
return signedTx, nil
345330
}
346331

332+
// initializeNonce initializes the nonce by taking the maximum of database nonce and pending nonce.
333+
func (s *Sender) initializeNonce() (uint64, error) {
334+
// Get maximum nonce from database
335+
dbNonce, err := s.pendingTransactionOrm.GetMaxNonceBySenderAddress(s.ctx, s.transactionSigner.GetAddr().Hex())
336+
if err != nil {
337+
return 0, fmt.Errorf("failed to get max nonce from database for address %s, err: %w", s.transactionSigner.GetAddr().Hex(), err)
338+
}
339+
340+
// Get pending nonce from the client
341+
pendingNonce, err := s.client.PendingNonceAt(s.ctx, s.transactionSigner.GetAddr())
342+
if err != nil {
343+
return 0, fmt.Errorf("failed to get pending nonce for address %s, err: %w", s.transactionSigner.GetAddr().Hex(), err)
344+
}
345+
346+
// Take the maximum of pending nonce and (db nonce + 1)
347+
// Database stores the used nonce, so the next available nonce should be dbNonce + 1
348+
// When dbNonce is -1 (no records), dbNonce + 1 = 0, which is correct
349+
nextDbNonce := uint64(dbNonce + 1)
350+
var finalNonce uint64
351+
if pendingNonce > nextDbNonce {
352+
finalNonce = pendingNonce
353+
} else {
354+
finalNonce = nextDbNonce
355+
}
356+
357+
log.Info("nonce initialization", "address", s.transactionSigner.GetAddr().Hex(), "maxDbNonce", dbNonce, "nextDbNonce", nextDbNonce, "pendingNonce", pendingNonce, "finalNonce", finalNonce)
358+
359+
return finalNonce, nil
360+
}
361+
347362
// resetNonce reset nonce if send signed tx failed.
348-
func (s *Sender) resetNonce(ctx context.Context) {
349-
nonce, err := s.client.PendingNonceAt(ctx, s.transactionSigner.GetAddr())
363+
func (s *Sender) resetNonce() error {
364+
nonce, err := s.initializeNonce()
350365
if err != nil {
351-
log.Warn("failed to reset nonce", "address", s.transactionSigner.GetAddr().String(), "err", err)
352-
return
366+
log.Error("failed to reset nonce", "address", s.transactionSigner.GetAddr().String(), "err", err)
367+
return fmt.Errorf("failed to reset nonce, err: %w", err)
353368
}
369+
log.Info("reset nonce", "address", s.transactionSigner.GetAddr().String(), "nonce", nonce)
354370
s.transactionSigner.SetNonce(nonce)
371+
return nil
355372
}
356373

357374
func (s *Sender) createReplacingTransaction(tx *gethTypes.Transaction, baseFee, blobBaseFee uint64) (*gethTypes.Transaction, error) {

rollup/internal/orm/orm_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -603,10 +603,10 @@ func TestPendingTransaction_GetMaxNonceBySenderAddress(t *testing.T) {
603603
assert.NoError(t, err)
604604
assert.NoError(t, migrate.ResetDB(sqlDB))
605605

606-
// When there are no transactions for this sender address, should return 0
606+
// When there are no transactions for this sender address, should return -1
607607
maxNonce, err := pendingTransactionOrm.GetMaxNonceBySenderAddress(context.Background(), "0xdeadbeef")
608608
assert.NoError(t, err)
609-
assert.Equal(t, uint64(0), maxNonce)
609+
assert.Equal(t, int64(-1), maxNonce)
610610

611611
// Insert two transactions with different nonces for the same sender address
612612
senderMeta := &SenderMeta{
@@ -653,5 +653,5 @@ func TestPendingTransaction_GetMaxNonceBySenderAddress(t *testing.T) {
653653
// Now the max nonce for this sender should be 3
654654
maxNonce, err = pendingTransactionOrm.GetMaxNonceBySenderAddress(context.Background(), senderMeta.Address.String())
655655
assert.NoError(t, err)
656-
assert.Equal(t, uint64(3), maxNonce)
656+
assert.Equal(t, int64(3), maxNonce)
657657
}

rollup/internal/orm/pending_transaction.go

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package orm
33
import (
44
"bytes"
55
"context"
6+
"database/sql"
67
"fmt"
78
"time"
89

@@ -209,18 +210,23 @@ func (o *PendingTransaction) UpdateOtherTransactionsAsFailedByNonce(ctx context.
209210
}
210211

211212
// GetMaxNonceBySenderAddress retrieves the maximum nonce for a specific sender address.
212-
// Returns 0 if no transactions are found for the given address.
213-
func (o *PendingTransaction) GetMaxNonceBySenderAddress(ctx context.Context, senderAddress string) (uint64, error) {
214-
db := o.db.WithContext(ctx)
215-
db = db.Model(&PendingTransaction{})
216-
db = db.Where("sender_address = ?", senderAddress)
217-
var maxNonce uint64
218-
row := db.Model(&PendingTransaction{}).
219-
Select("COALESCE(MAX(nonce), 0)").
213+
// Returns -1 if no transactions are found for the given address.
214+
func (o *PendingTransaction) GetMaxNonceBySenderAddress(ctx context.Context, senderAddress string) (int64, error) {
215+
var maxNonce sql.NullInt64
216+
217+
row := o.db.WithContext(ctx).
218+
Model(&PendingTransaction{}).
219+
Select("MAX(nonce)").
220220
Where("sender_address = ?", senderAddress).
221221
Row()
222+
222223
if err := row.Scan(&maxNonce); err != nil {
223-
return 0, fmt.Errorf("failed to get max nonce by sender address, address: %s, err: %w", senderAddress, err)
224+
return -1, fmt.Errorf("failed to get max nonce by sender address, address: %s, err: %w", senderAddress, err)
225+
}
226+
227+
if !maxNonce.Valid {
228+
return -1, nil
224229
}
225-
return maxNonce, nil
230+
231+
return maxNonce.Int64, nil
226232
}

0 commit comments

Comments
 (0)