Commit 2aab09b8 authored by OptimismBot's avatar OptimismBot Committed by GitHub

Merge pull request #5536 from ethereum-optimism/jg/handle_l2_reorgs_cleanly

op-batcher: Properly drain state on L2 reorgs
parents 4c3c1621 7e389c7d
...@@ -187,13 +187,15 @@ func (l *BatchSubmitter) Stop(ctx context.Context) error { ...@@ -187,13 +187,15 @@ func (l *BatchSubmitter) Stop(ctx context.Context) error {
// 2. Check if the sync status is valid or if we are all the way up to date // 2. Check if the sync status is valid or if we are all the way up to date
// 3. Check if it needs to initialize state OR it is lagging (todo: lagging just means race condition?) // 3. Check if it needs to initialize state OR it is lagging (todo: lagging just means race condition?)
// 4. Load all new blocks into the local state. // 4. Load all new blocks into the local state.
func (l *BatchSubmitter) loadBlocksIntoState(ctx context.Context) { // If there is a reorg, it will reset the last stored block but not clear the internal state so
// the state can be flushed to L1.
func (l *BatchSubmitter) loadBlocksIntoState(ctx context.Context) error {
start, end, err := l.calculateL2BlockRangeToStore(ctx) start, end, err := l.calculateL2BlockRangeToStore(ctx)
if err != nil { if err != nil {
l.log.Warn("Error calculating L2 block range", "err", err) l.log.Warn("Error calculating L2 block range", "err", err)
return return err
} else if start.Number >= end.Number { } else if start.Number >= end.Number {
return return errors.New("start number is >= end number")
} }
var latestBlock *types.Block var latestBlock *types.Block
...@@ -202,12 +204,11 @@ func (l *BatchSubmitter) loadBlocksIntoState(ctx context.Context) { ...@@ -202,12 +204,11 @@ func (l *BatchSubmitter) loadBlocksIntoState(ctx context.Context) {
block, err := l.loadBlockIntoState(ctx, i) block, err := l.loadBlockIntoState(ctx, i)
if errors.Is(err, ErrReorg) { if errors.Is(err, ErrReorg) {
l.log.Warn("Found L2 reorg", "block_number", i) l.log.Warn("Found L2 reorg", "block_number", i)
l.state.Clear()
l.lastStoredBlock = eth.BlockID{} l.lastStoredBlock = eth.BlockID{}
return return err
} else if err != nil { } else if err != nil {
l.log.Warn("failed to load block into state", "err", err) l.log.Warn("failed to load block into state", "err", err)
return return err
} }
l.lastStoredBlock = eth.ToBlockID(block) l.lastStoredBlock = eth.ToBlockID(block)
latestBlock = block latestBlock = block
...@@ -216,10 +217,11 @@ func (l *BatchSubmitter) loadBlocksIntoState(ctx context.Context) { ...@@ -216,10 +217,11 @@ func (l *BatchSubmitter) loadBlocksIntoState(ctx context.Context) {
l2ref, err := derive.L2BlockToBlockRef(latestBlock, &l.Rollup.Genesis) l2ref, err := derive.L2BlockToBlockRef(latestBlock, &l.Rollup.Genesis)
if err != nil { if err != nil {
l.log.Warn("Invalid L2 block loaded into state", "err", err) l.log.Warn("Invalid L2 block loaded into state", "err", err)
return return err
} }
l.metr.RecordL2BlocksLoaded(l2ref) l.metr.RecordL2BlocksLoaded(l2ref)
return nil
} }
// loadBlockIntoState fetches & stores a single block into `state`. It returns the block it loaded. // loadBlockIntoState fetches & stores a single block into `state`. It returns the block it loaded.
...@@ -294,7 +296,15 @@ func (l *BatchSubmitter) loop() { ...@@ -294,7 +296,15 @@ func (l *BatchSubmitter) loop() {
for { for {
select { select {
case <-ticker.C: case <-ticker.C:
l.loadBlocksIntoState(l.shutdownCtx) if err := l.loadBlocksIntoState(l.shutdownCtx); errors.Is(err, ErrReorg) {
err := l.state.Close()
if err != nil {
l.log.Error("error closing the channel manager to handle a L2 reorg", "err", err)
}
l.publishStateToL1(queue, receiptsCh, true)
l.state.Clear()
continue
}
l.publishStateToL1(queue, receiptsCh, false) l.publishStateToL1(queue, receiptsCh, false)
case r := <-receiptsCh: case r := <-receiptsCh:
l.handleReceipt(r) l.handleReceipt(r)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment