-
Notifications
You must be signed in to change notification settings - Fork 22
fix: Reset streamer in case of L1 reorg causing batch tx not to go through #1045
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: integration-v3.9.8
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1855,9 +1855,8 @@ func (b *BatchPoster) MaybePostSequencerBatch(ctx context.Context) (bool, error) | |
| } | ||
| if b.building == nil || b.building.startMsgCount != batchPosition.MessageCount { | ||
| if b.espressoStreamer != nil { | ||
| b.espressoStreamer.AdvanceTo(uint64(batchPosition.MessageCount)) | ||
| if b.espressoRestarting { | ||
| // Reset only once | ||
| // Reset on startup | ||
| log.Info("resetting streamer to parent chain", "messageCount", batchPosition.MessageCount) | ||
| // Fallback. For existing queued batches, we don't have the hotshot block number, so we reset to the parent chain. | ||
| b.resetStreamerToParentChainOrConfigHotshotBlock(batchPosition.MessageCount, ctx) | ||
|
|
@@ -1878,6 +1877,14 @@ func (b *BatchPoster) MaybePostSequencerBatch(ctx context.Context) (bool, error) | |
| log.Info("submitted pending transactions after restart", "from", batchPosition.MessageCount, "count", len(queue)) | ||
| } | ||
| b.espressoRestarting = false | ||
| } else { | ||
| if uint64(batchPosition.MessageCount) < b.espressoStreamer.GetCurrentMessagePos() { | ||
| // Batch position moved backwards probably due to l1 reorg, try and resync the blocks from hotshot | ||
| log.Warn("resetting espresso streamer to parent chain (L1 reorg?)", "messageCount", batchPosition.MessageCount) | ||
| b.resetStreamerToParentChainOrConfigHotshotBlock(batchPosition.MessageCount, ctx) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: The reorg detection compares One thing worth considering: after the reorg reset, the streamer's The window is small, but in theory:
Step 3 would clean up step 2's stale data, so this is safe in practice. Just flagging for awareness. |
||
| } else { | ||
| b.espressoStreamer.AdvanceTo(uint64(batchPosition.MessageCount)) | ||
| } | ||
| } | ||
| } | ||
| latestHeader, err := b.l1Reader.LastHeader(ctx) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -44,6 +44,8 @@ type EspressoStreamerInterface interface { | |
| Advance() | ||
| // Reset sets the current message position and the next hotshot block number. | ||
| Reset(currentMessagePos uint64, currentHostshotBlock uint64) | ||
| // GetCurrentMessagePos returns the current message position of the streamer. | ||
| GetCurrentMessagePos() uint64 | ||
| // RecordTimeDurationBetweenHotshotAndCurrentBlock records the time duration between | ||
| // the next hotshot block and the current block. | ||
| RecordTimeDurationBetweenHotshotAndCurrentBlock(nextHotshotBlock uint64, blockProductionTime time.Time) | ||
|
|
@@ -225,6 +227,12 @@ func (s *EspressoStreamer) Advance() { | |
| s.currentMessagePos += 1 | ||
| } | ||
|
|
||
| func (s *EspressoStreamer) GetCurrentMessagePos() uint64 { | ||
| s.messageLock.RLock() | ||
| defer s.messageLock.RUnlock() | ||
| return s.currentMessagePos | ||
| } | ||
|
|
||
| func (s *EspressoStreamer) AdvanceTo(toPos uint64) { | ||
| s.messageLock.Lock() | ||
| defer s.messageLock.Unlock() | ||
|
|
@@ -370,11 +378,8 @@ func (s *EspressoStreamer) parseEspressoTransaction(tx espressoTypes.Bytes, l1He | |
| s.messageLock.Lock() | ||
| defer s.messageLock.Unlock() | ||
| for i, message := range messages { | ||
| var messageWithMetadata arbostypes.MessageWithMetadata | ||
| err = rlp.DecodeBytes(message, &messageWithMetadata) | ||
| if err != nil { | ||
| log.Warn("failed to decode message", "err", err) | ||
| // Instead of returnning an error, we should just skip this message | ||
| if _, exists := s.messageWithMetadataAndPos[indices[i]]; exists { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what is this code doing? I am not sure I understand
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it just checks if the position is already in the streamer. Without this check it was overwriting an existing message with the later message instead of just taking the first message |
||
| log.Warn("duplicate message position, discarding", "pos", indices[i]) | ||
| continue | ||
| } | ||
|
lukeiannucci marked this conversation as resolved.
|
||
|
|
||
|
|
@@ -383,6 +388,14 @@ func (s *EspressoStreamer) parseEspressoTransaction(tx espressoTypes.Bytes, l1He | |
| continue | ||
| } | ||
|
|
||
| var messageWithMetadata arbostypes.MessageWithMetadata | ||
| err = rlp.DecodeBytes(message, &messageWithMetadata) | ||
| if err != nil { | ||
| log.Warn("failed to decode message", "err", err) | ||
| // Instead of returnning an error, we should just skip this message | ||
| continue | ||
| } | ||
|
|
||
| msg := &MessageWithMetadataAndPos{ | ||
| MessageWithMeta: messageWithMetadata, | ||
| Pos: indices[i], | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what if the MessagePos is after the current message pos and has not yet arrived in the streamer? Will we keep resetting then in this loop?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I dont quite understand the question. But how it works now, is we only advance the streamer when the batch is posted (its part of this else check). So streamer current position will never be ahead of batch position, only equal to it. So, it will only reset if for some reason the batch position is moved backwards. Does this make sense?