-
Notifications
You must be signed in to change notification settings - Fork 105
feat(mempool): Add TxTracker support for handling temporary rejections #646
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
| for _, txs := range all { | ||
| for _, tx := range txs { | ||
| if err = rlp.Encode(replacement, tx); err != nil { | ||
| replacement.Close() | ||
| return err | ||
| } | ||
| } | ||
| journaled += len(txs) | ||
| } |
Check warning
Code scanning / CodeQL
Iteration over map Warning
| for _, txs := range all { | ||
| for _, tx := range txs { | ||
| if err = rlp.Encode(replacement, tx); err != nil { | ||
| replacement.Close() |
Check warning
Code scanning / CodeQL
Writable file handle closed without error handling Warning
call to OpenFile
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 1 month ago
To fix this issue, always check and handle errors returned by replacement.Close(). In this code, there are two places where replacement.Close() is called:
- In the error path inside the loop, after a failed
rlp.Encode - After the loop, when all transactions have been written
In both cases, the error from Close() should be checked. In the error path, if rlp.Encode fails, and replacement.Close() also fails, both errors are relevant, but returning the first error (the encoding error) is conventionally favored, though logging the close error could also be considered. In the success path, if replacement.Close() fails, its error should be returned to the caller instead of pretending everything succeeded.
The code should be updated to:
- Check the error from
replacement.Close(). - In the error path, attempt to close and return the error from
rlp.Encode(possibly logging any close error). - In the normal path, after
replacement.Close(), return any error from closing (if present).
No extra imports or new methods are needed, just additional error handling.
-
Copy modified lines R150-R153 -
Copy modified lines R159-R161
| @@ -147,13 +147,18 @@ | ||
| for _, txs := range all { | ||
| for _, tx := range txs { | ||
| if err = rlp.Encode(replacement, tx); err != nil { | ||
| replacement.Close() | ||
| closeErr := replacement.Close() | ||
| if closeErr != nil { | ||
| // Optionally, log closeErr here using `log.Warn`, since only one error can be returned. | ||
| } | ||
| return err | ||
| } | ||
| } | ||
| journaled += len(txs) | ||
| } | ||
| replacement.Close() | ||
| if err := replacement.Close(); err != nil { | ||
| return err | ||
| } | ||
|
|
||
| // Replace the live journal with the newly generated one | ||
| if err = os.Rename(journal.path+".new", journal.path); err != nil { |
| } | ||
| journaled += len(txs) | ||
| } | ||
| replacement.Close() |
Check warning
Code scanning / CodeQL
Writable file handle closed without error handling Warning
call to OpenFile
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 1 month ago
General approach:
Explicitly check the error returned by replacement.Close() on line 156, and propagate it up by returning if it is non-nil.
Detailed steps:
- After the loop writing to
replacement, instead of callingreplacement.Close()and discarding its error, check it. - If this error is non-nil, return it immediately, just as is done for other errors within
rotate. - This preserves the existing functional behavior but closes the bug where a late error would be suppressed.
- No additional imports or helpers are needed. Just update the close call and error handling.
Where to change:
- In
mempool/txpool/locals/journal.go, in therotatefunction, around line 156 (after writing transactions and before renaming the file).
-
Copy modified lines R156-R158
| @@ -153,7 +153,9 @@ | ||
| } | ||
| journaled += len(txs) | ||
| } | ||
| replacement.Close() | ||
| if err := replacement.Close(); err != nil { | ||
| return err | ||
| } | ||
|
|
||
| // Replace the live journal with the newly generated one | ||
| if err = os.Rename(journal.path+".new", journal.path); err != nil { |
| for sender, txs := range tracker.byAddr { | ||
| // Wipe the stales | ||
| stales := txs.Forward(tracker.pool.Nonce(sender)) | ||
| for _, tx := range stales { | ||
| delete(tracker.all, tx.Hash()) | ||
| } | ||
| numStales += len(stales) | ||
|
|
||
| // Check the non-stale | ||
| for _, tx := range txs.Flatten() { | ||
| if tracker.pool.Has(tx.Hash()) { | ||
| numOk++ | ||
| continue | ||
| } | ||
| resubmits = append(resubmits, tx) | ||
| } | ||
| } |
Check warning
Code scanning / CodeQL
Iteration over map Warning
| for _, tx := range tracker.all { | ||
| addr, _ := types.Sender(tracker.signer, tx) | ||
| rejournal[addr] = append(rejournal[addr], tx) | ||
| } |
Check warning
Code scanning / CodeQL
Iteration over map Warning
| for _, list := range rejournal { | ||
| // cmp(a, b) should return a negative number when a < b, | ||
| slices.SortFunc(list, func(a, b *types.Transaction) int { | ||
| return int(a.Nonce() - b.Nonce()) | ||
| }) | ||
| } |
Check warning
Code scanning / CodeQL
Iteration over map Warning
| // layer was also initialized to spawn any goroutines required by the service. | ||
| func (tracker *TxTracker) Start() error { | ||
| tracker.wg.Add(1) | ||
| go tracker.loop() |
Check notice
Code scanning / CodeQL
Spawning a Go routine Note
| defer tracker.journal.close() | ||
| } | ||
| var ( | ||
| lastJournal = time.Now() |
Check warning
Code scanning / CodeQL
Calling the system time Warning
| if checkJournal { | ||
| // Lock to prevent journal.rotate <-> journal.insert (via TrackAll) conflicts | ||
| tracker.mu.Lock() | ||
| lastJournal = time.Now() |
Check warning
Code scanning / CodeQL
Calling the system time Warning
Description
Closes: #500
Author Checklist
I have...
mainbranch