-
Couldn't load subscription status.
- Fork 106
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 2 hours ago
To fix the problem, we must ensure that any error returned by replacement.Close() is neither ignored nor silently discarded. Specifically, in the event that a write (rlp.Encode) fails inside the loop, the code should close the file and capture any error from Close(). If Close() also fails, both errors should be reported—ideally by combining them. The canonical way in Go is to chain or wrap the Close error with the initial error (if both occur). This can be done with Go's errors.Join (Go 1.20+) or, for older Go, by concatenating the messages or using a helper function. Since the import errors is already present, and Go 1.20+'s errors.Join is standard, I'll use that.
The fix consists of:
- Not just calling
replacement.Close()without checking, but capturing its error. - If both
rlp.Encodeandreplacement.Closeerror, returnerrors.Join(encodeErr, closeErr). - If only one errors, return that error.
- Changing only the relevant region of the file in the shown snippet (
mempool/txpool/locals/journal.go).
-
Copy modified lines R150-R153
| @@ -147,7 +147,10 @@ | ||
| for _, txs := range all { | ||
| for _, tx := range txs { | ||
| if err = rlp.Encode(replacement, tx); err != nil { | ||
| replacement.Close() | ||
| closeErr := replacement.Close() | ||
| if closeErr != nil { | ||
| return errors.Join(err, closeErr) | ||
| } | ||
| return err | ||
| } | ||
| } |
| } | ||
| 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 2 hours ago
To fix the problem, always check the error result returned by replacement.Close() (line 156) and handle it as you do for other file operations in the same function. The best way, patterned after the rest of the function, is to assign the error returned from replacement.Close() to err, and if it is non-nil, return it as the function error immediately. This ensures that any issue closing the file is surfaced and handled, avoiding silent data loss.
Changes needed:
- In mempool/txpool/locals/journal.go, in the
rotatemethod, replace the call at line 156 fromreplacement.Close()to:if err = replacement.Close(); err != nil { return err }
No new imports or method definitions are necessary, as this is the pattern for error handling already used in this function.
-
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