From ba90549d82bb0a4671a2c2f52b17e44480cc3874 Mon Sep 17 00:00:00 2001
From: Jeffery Walsh <cyberhorsey@gmail.com>
Date: Thu, 4 May 2023 19:34:36 -0700
Subject: [PATCH 01/25] ref

---
 .github/workflows/test.yml     | 1 -
 integration_test/entrypoint.sh | 3 ++-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 0bffce707..4e1ab2480 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -45,7 +45,6 @@ jobs:
         with:
           repository: taikoxyz/taiko-mono
           path: ${{ env.TAIKO_MONO_DIR }}
-          ref: get_oracle_prover
 
       - name: Install Foundry
         uses: foundry-rs/foundry-toolchain@v1
diff --git a/integration_test/entrypoint.sh b/integration_test/entrypoint.sh
index 8f10b1681..ec951f993 100755
--- a/integration_test/entrypoint.sh
+++ b/integration_test/entrypoint.sh
@@ -32,6 +32,7 @@ L1_SIGNAL_SERVICE_CONTRACT_ADDRESS=$(echo $DEPLOYMENT_JSON | jq '.signal_service
 trap "docker compose -f $TESTNET_CONFIG down -v" EXIT INT KILL ERR
 
 RUN_TESTS=${RUN_TESTS:-false}
+PACKAGE=${PACKAGE:-...}
 
 echo "TAIKO_L1_CONTRACT_ADDRESS: $TAIKO_L1_CONTRACT_ADDRESS"
 echo "L1_SIGNAL_SERVICE_CONTRACT_ADDRESS: $L1_SIGNAL_SERVICE_CONTRACT_ADDRESS"
@@ -50,7 +51,7 @@ if [ "$RUN_TESTS" == "true" ]; then
     L2_SUGGESTED_FEE_RECIPIENT=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 \
     L1_PROVER_PRIVATE_KEY=59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d \
     JWT_SECRET=$DIR/nodes/jwt.hex \
-        go test -v -p=1 ./... -coverprofile=coverage.out -covermode=atomic -timeout=300s
+        go test -v -p=1 ./$PACKAGE -coverprofile=coverage.out -covermode=atomic -timeout=300s
 else
     echo "💻 Local dev net started"
     docker compose -f $TESTNET_CONFIG logs -f l2_execution_engine

From e6124e6ec9a193e98ed3ce1cea83d5b9b26c3ab7 Mon Sep 17 00:00:00 2001
From: Jeffery Walsh <cyberhorsey@gmail.com>
Date: Wed, 10 May 2023 12:17:25 -0700
Subject: [PATCH 02/25] handle reorg on events being removed

---
 pkg/chain_iterator/block_batch_iterator.go    | 27 +++++++++++++++----
 .../block_batch_iterator_test.go              |  3 +++
 .../event_iterator/block_proposed_iterator.go |  4 +--
 .../event_iterator/block_proven_iterator.go   |  4 +--
 4 files changed, 29 insertions(+), 9 deletions(-)

diff --git a/pkg/chain_iterator/block_batch_iterator.go b/pkg/chain_iterator/block_batch_iterator.go
index 4479b4e7e..5d84f0ea7 100644
--- a/pkg/chain_iterator/block_batch_iterator.go
+++ b/pkg/chain_iterator/block_batch_iterator.go
@@ -29,6 +29,7 @@ type OnBlocksFunc func(
 	ctx context.Context,
 	start, end *types.Header,
 	updateCurrentFunc UpdateCurrentFunc,
+	onReorgFunc OnReorgFunc,
 	endIterFunc EndIterFunc,
 ) error
 
@@ -38,6 +39,9 @@ type UpdateCurrentFunc func(*types.Header)
 // EndIterFunc ends the current iteration.
 type EndIterFunc func()
 
+// OnReorgFunc handles a reorganization from the source chain.
+type OnReorgFunc func() error
+
 // BlockBatchIterator iterates the blocks in batches between the given start and end heights,
 // with the awareness of reorganization.
 type BlockBatchIterator struct {
@@ -205,7 +209,7 @@ func (i *BlockBatchIterator) iter() (err error) {
 		return err
 	}
 
-	if err := i.onBlocks(i.ctx, i.current, endHeader, i.updateCurrent, i.end); err != nil {
+	if err := i.onBlocks(i.ctx, i.current, endHeader, i.updateCurrent, i.rewindOnReorgDetected, i.end); err != nil {
 		return err
 	}
 
@@ -252,7 +256,7 @@ func (i *BlockBatchIterator) reverseIter() (err error) {
 		return err
 	}
 
-	if err := i.onBlocks(i.ctx, startHeader, i.current, i.updateCurrent, i.end); err != nil {
+	if err := i.onBlocks(i.ctx, startHeader, i.current, i.updateCurrent, i.rewindOnReorgDetected, i.end); err != nil {
 		return err
 	}
 
@@ -282,6 +286,8 @@ func (i *BlockBatchIterator) end() {
 
 // ensureCurrentNotReorged checks if the iterator.current cursor was reorged, if was, will
 // rewind back `ReorgRewindDepth` blocks.
+// reorg is also detected on the iteration of the event later, by checking
+// event.Raw.Removed, which will also call `i.rewindOnReorgDetected` to rewind back
 func (i *BlockBatchIterator) ensureCurrentNotReorged() error {
 	current, err := i.client.HeaderByHash(i.ctx, i.current.Hash())
 	if err != nil && !errors.Is(err, ethereum.NotFound) {
@@ -293,7 +299,13 @@ func (i *BlockBatchIterator) ensureCurrentNotReorged() error {
 		return nil
 	}
 
-	// Reorg detected, rewind back `ReorgRewindDepth` blocks
+	// reorged
+	return i.rewindOnReorgDetected()
+}
+
+// rewindOnReorgDetected rewinds back `ReorgRewindDepth` blocks and sets i.current
+// to a stable block
+func (i *BlockBatchIterator) rewindOnReorgDetected() error {
 	var newCurrentHeight uint64
 	if i.current.Number.Uint64() <= ReorgRewindDepth {
 		newCurrentHeight = 0
@@ -301,6 +313,11 @@ func (i *BlockBatchIterator) ensureCurrentNotReorged() error {
 		newCurrentHeight = i.current.Number.Uint64() - ReorgRewindDepth
 	}
 
-	i.current, err = i.client.HeaderByNumber(i.ctx, new(big.Int).SetUint64(newCurrentHeight))
-	return err
+	current, err := i.client.HeaderByNumber(i.ctx, new(big.Int).SetUint64(newCurrentHeight))
+	if err != nil {
+		return err
+	}
+
+	i.current = current
+	return nil
 }
diff --git a/pkg/chain_iterator/block_batch_iterator_test.go b/pkg/chain_iterator/block_batch_iterator_test.go
index fd809936d..760c50ec2 100644
--- a/pkg/chain_iterator/block_batch_iterator_test.go
+++ b/pkg/chain_iterator/block_batch_iterator_test.go
@@ -33,6 +33,7 @@ func (s *BlockBatchIteratorTestSuite) TestIter() {
 			ctx context.Context,
 			start, end *types.Header,
 			updateCurrentFunc UpdateCurrentFunc,
+			onReorgFunc OnReorgFunc,
 			endIterFunc EndIterFunc,
 		) error {
 			s.Equal(lastEnd.Uint64(), start.Number.Uint64())
@@ -68,6 +69,7 @@ func (s *BlockBatchIteratorTestSuite) TestIterReverse() {
 			ctx context.Context,
 			start, end *types.Header,
 			updateCurrentFunc UpdateCurrentFunc,
+			onReorgFunc OnReorgFunc,
 			endIterFunc EndIterFunc,
 		) error {
 			s.Equal(lastStart.Uint64(), end.Number.Uint64())
@@ -99,6 +101,7 @@ func (s *BlockBatchIteratorTestSuite) TestIterEndFunc() {
 			ctx context.Context,
 			start, end *types.Header,
 			updateCurrentFunc UpdateCurrentFunc,
+			onReorgFunc OnReorgFunc,
 			endIterFunc EndIterFunc,
 		) error {
 			s.Equal(lastEnd.Uint64(), start.Number.Uint64())
diff --git a/pkg/chain_iterator/event_iterator/block_proposed_iterator.go b/pkg/chain_iterator/event_iterator/block_proposed_iterator.go
index 6928f09a3..74658e3c8 100644
--- a/pkg/chain_iterator/event_iterator/block_proposed_iterator.go
+++ b/pkg/chain_iterator/event_iterator/block_proposed_iterator.go
@@ -105,6 +105,7 @@ func assembleBlockProposedIteratorCallback(
 		ctx context.Context,
 		start, end *types.Header,
 		updateCurrentFunc chainIterator.UpdateCurrentFunc,
+		onReorgFunc chainIterator.OnReorgFunc,
 		endFunc chainIterator.EndIterFunc,
 	) error {
 		endHeight := end.Number.Uint64()
@@ -120,9 +121,8 @@ func assembleBlockProposedIteratorCallback(
 		for iter.Next() {
 			event := iter.Event
 
-			// Skip if reorged.
 			if event.Raw.Removed {
-				continue
+				return onReorgFunc()
 			}
 
 			if err := callback(ctx, event, eventIter.end); err != nil {
diff --git a/pkg/chain_iterator/event_iterator/block_proven_iterator.go b/pkg/chain_iterator/event_iterator/block_proven_iterator.go
index 39d8bf1fd..8228c39e6 100644
--- a/pkg/chain_iterator/event_iterator/block_proven_iterator.go
+++ b/pkg/chain_iterator/event_iterator/block_proven_iterator.go
@@ -101,6 +101,7 @@ func assembleBlockProvenIteratorCallback(
 		ctx context.Context,
 		start, end *types.Header,
 		updateCurrentFunc chainIterator.UpdateCurrentFunc,
+		onReorgFunc chainIterator.OnReorgFunc,
 		endFunc chainIterator.EndIterFunc,
 	) error {
 		endHeight := end.Number.Uint64()
@@ -116,9 +117,8 @@ func assembleBlockProvenIteratorCallback(
 		for iter.Next() {
 			event := iter.Event
 
-			// Skip if reorged.
 			if event.Raw.Removed {
-				continue
+				return onReorgFunc()
 			}
 
 			if err := callback(ctx, event, eventIter.end); err != nil {

From fca8bfb4fae9f2f9919a29ae525313cd1e504dd3 Mon Sep 17 00:00:00 2001
From: Jeffery Walsh <cyberhorsey@gmail.com>
Date: Wed, 10 May 2023 14:35:10 -0700
Subject: [PATCH 03/25] comment

---
 pkg/chain_iterator/block_batch_iterator.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pkg/chain_iterator/block_batch_iterator.go b/pkg/chain_iterator/block_batch_iterator.go
index 5d84f0ea7..fa7dd5d3f 100644
--- a/pkg/chain_iterator/block_batch_iterator.go
+++ b/pkg/chain_iterator/block_batch_iterator.go
@@ -304,7 +304,7 @@ func (i *BlockBatchIterator) ensureCurrentNotReorged() error {
 }
 
 // rewindOnReorgDetected rewinds back `ReorgRewindDepth` blocks and sets i.current
-// to a stable block
+// to a stable block, or 0 if it's less than `ReorgRewindDepth`.
 func (i *BlockBatchIterator) rewindOnReorgDetected() error {
 	var newCurrentHeight uint64
 	if i.current.Number.Uint64() <= ReorgRewindDepth {

From a7bbfe2056fd7630ad55b4bea6be5be504a83c62 Mon Sep 17 00:00:00 2001
From: Jeffery Walsh <cyberhorsey@gmail.com>
Date: Wed, 10 May 2023 15:32:13 -0700
Subject: [PATCH 04/25] block batch iterator test

---
 pkg/chain_iterator/block_batch_iterator.go    | 36 +++++++++++----
 .../block_batch_iterator_test.go              | 46 +++++++++++++++++++
 2 files changed, 73 insertions(+), 9 deletions(-)

diff --git a/pkg/chain_iterator/block_batch_iterator.go b/pkg/chain_iterator/block_batch_iterator.go
index fa7dd5d3f..fe72e566e 100644
--- a/pkg/chain_iterator/block_batch_iterator.go
+++ b/pkg/chain_iterator/block_batch_iterator.go
@@ -16,7 +16,7 @@ import (
 
 const (
 	DefaultBlocksReadPerEpoch = 1000
-	ReorgRewindDepth          = 20
+	DefaultReorgRewindDepth   = 20
 )
 
 var (
@@ -55,6 +55,8 @@ type BlockBatchIterator struct {
 	onBlocks           OnBlocksFunc
 	isEnd              bool
 	reverse            bool
+	reorgRewindDepth   uint64
+	onReorg            OnReorgFunc
 }
 
 // BlockBatchIteratorConfig represents the configs of a block batch iterator.
@@ -65,6 +67,8 @@ type BlockBatchIteratorConfig struct {
 	EndHeight             *big.Int
 	OnBlocks              OnBlocksFunc
 	Reverse               bool
+	ReorgRewindDepth      *uint64
+	OnReorg               OnReorgFunc
 }
 
 // NewBlockBatchIterator creates a new block batch iterator instance.
@@ -104,13 +108,27 @@ func NewBlockBatchIterator(ctx context.Context, cfg *BlockBatchIteratorConfig) (
 		}
 	}
 
+	var reorgRewindDepth uint64
+	if cfg.ReorgRewindDepth != nil {
+		reorgRewindDepth = *cfg.ReorgRewindDepth
+	} else {
+		reorgRewindDepth = DefaultReorgRewindDepth
+	}
+
 	iterator := &BlockBatchIterator{
-		ctx:         ctx,
-		client:      cfg.Client,
-		chainID:     chainID,
-		startHeight: cfg.StartHeight.Uint64(),
-		onBlocks:    cfg.OnBlocks,
-		reverse:     cfg.Reverse,
+		ctx:              ctx,
+		client:           cfg.Client,
+		chainID:          chainID,
+		startHeight:      cfg.StartHeight.Uint64(),
+		onBlocks:         cfg.OnBlocks,
+		reverse:          cfg.Reverse,
+		reorgRewindDepth: reorgRewindDepth,
+	}
+
+	if cfg.OnReorg != nil {
+		iterator.onReorg = cfg.OnReorg
+	} else {
+		iterator.onReorg = iterator.rewindOnReorgDetected
 	}
 
 	if cfg.Reverse {
@@ -307,10 +325,10 @@ func (i *BlockBatchIterator) ensureCurrentNotReorged() error {
 // to a stable block, or 0 if it's less than `ReorgRewindDepth`.
 func (i *BlockBatchIterator) rewindOnReorgDetected() error {
 	var newCurrentHeight uint64
-	if i.current.Number.Uint64() <= ReorgRewindDepth {
+	if i.current.Number.Uint64() <= i.reorgRewindDepth {
 		newCurrentHeight = 0
 	} else {
-		newCurrentHeight = i.current.Number.Uint64() - ReorgRewindDepth
+		newCurrentHeight = i.current.Number.Uint64() - i.reorgRewindDepth
 	}
 
 	current, err := i.client.HeaderByNumber(i.ctx, new(big.Int).SetUint64(newCurrentHeight))
diff --git a/pkg/chain_iterator/block_batch_iterator_test.go b/pkg/chain_iterator/block_batch_iterator_test.go
index 760c50ec2..39120c0df 100644
--- a/pkg/chain_iterator/block_batch_iterator_test.go
+++ b/pkg/chain_iterator/block_batch_iterator_test.go
@@ -116,6 +116,52 @@ func (s *BlockBatchIteratorTestSuite) TestIterEndFunc() {
 	s.Equal(lastEnd.Uint64(), maxBlocksReadPerEpoch)
 }
 
+func (s *BlockBatchIteratorTestSuite) TestIter_ReorgEncounteredWithRemovedEvent() {
+	var maxBlocksReadPerEpoch uint64 = 2
+	var reorgRewindDepth uint64 = 1
+
+	var reorgedBlocks = 0
+
+	headHeight, err := s.RpcClient.L1.BlockNumber(context.Background())
+	s.Nil(err)
+	s.Greater(headHeight, uint64(0))
+
+	lastEnd := common.Big0
+
+	iter, err := NewBlockBatchIterator(context.Background(), &BlockBatchIteratorConfig{
+		Client:                s.RpcClient.L1,
+		MaxBlocksReadPerEpoch: &maxBlocksReadPerEpoch,
+		StartHeight:           common.Big0,
+		EndHeight:             new(big.Int).SetUint64(headHeight),
+		ReorgRewindDepth:      &reorgRewindDepth,
+		OnReorg: func() error {
+			reorgedBlocks++
+			return nil
+		},
+		OnBlocks: func(
+			ctx context.Context,
+			start, end *types.Header,
+			updateCurrentFunc UpdateCurrentFunc,
+			onReorgFunc OnReorgFunc,
+			endIterFunc EndIterFunc,
+		) error {
+			// reorg every 2 blocks
+			if end.Number.Uint64()%2 == 0 {
+				return onReorgFunc()
+			}
+
+			s.Equal(lastEnd.Uint64(), start.Number.Uint64())
+			lastEnd = end.Number
+			return nil
+		},
+	})
+
+	s.Nil(err)
+	s.Nil(iter.Iter())
+	s.Equal(headHeight, lastEnd.Uint64())
+	s.Greater(reorgedBlocks, (headHeight/2 - 1))
+}
+
 func TestBlockBatchIteratorTestSuite(t *testing.T) {
 	suite.Run(t, new(BlockBatchIteratorTestSuite))
 }

From 2b6b00aba5ecdbe29fab7c3aed7ea62dbcf2e175 Mon Sep 17 00:00:00 2001
From: Jeffery Walsh <cyberhorsey@gmail.com>
Date: Wed, 10 May 2023 16:10:00 -0700
Subject: [PATCH 05/25] test

---
 pkg/chain_iterator/block_batch_iterator_test.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pkg/chain_iterator/block_batch_iterator_test.go b/pkg/chain_iterator/block_batch_iterator_test.go
index 39120c0df..75a819223 100644
--- a/pkg/chain_iterator/block_batch_iterator_test.go
+++ b/pkg/chain_iterator/block_batch_iterator_test.go
@@ -159,7 +159,7 @@ func (s *BlockBatchIteratorTestSuite) TestIter_ReorgEncounteredWithRemovedEvent(
 	s.Nil(err)
 	s.Nil(iter.Iter())
 	s.Equal(headHeight, lastEnd.Uint64())
-	s.Greater(reorgedBlocks, (headHeight/2 - 1))
+	s.Equal(reorgedBlocks, (headHeight/2 - 1))
 }
 
 func TestBlockBatchIteratorTestSuite(t *testing.T) {

From 5a9fbc6d0e449a166a83433472dffa646a701c74 Mon Sep 17 00:00:00 2001
From: Jeffery Walsh <cyberhorsey@gmail.com>
Date: Wed, 10 May 2023 16:18:50 -0700
Subject: [PATCH 06/25] reorg

---
 pkg/chain_iterator/block_batch_iterator_test.go | 1 +
 1 file changed, 1 insertion(+)

diff --git a/pkg/chain_iterator/block_batch_iterator_test.go b/pkg/chain_iterator/block_batch_iterator_test.go
index 75a819223..7c5d7de9e 100644
--- a/pkg/chain_iterator/block_batch_iterator_test.go
+++ b/pkg/chain_iterator/block_batch_iterator_test.go
@@ -136,6 +136,7 @@ func (s *BlockBatchIteratorTestSuite) TestIter_ReorgEncounteredWithRemovedEvent(
 		ReorgRewindDepth:      &reorgRewindDepth,
 		OnReorg: func() error {
 			reorgedBlocks++
+			lastEnd = new(big.Int).Sub(lastEnd, new(big.Int).SetUint64(reorgRewindDepth))
 			return nil
 		},
 		OnBlocks: func(

From cac931677acb2c85a3f72e7ee38fb313f968e3b0 Mon Sep 17 00:00:00 2001
From: Jeffery Walsh <cyberhorsey@gmail.com>
Date: Wed, 10 May 2023 17:32:47 -0700
Subject: [PATCH 07/25] reorg test

---
 Makefile                                      |  1 +
 pkg/chain_iterator/block_batch_iterator.go    |  4 +--
 .../block_batch_iterator_test.go              | 26 ++++++++++++-------
 3 files changed, 19 insertions(+), 12 deletions(-)

diff --git a/Makefile b/Makefile
index 0af1b1c0b..eda456931 100644
--- a/Makefile
+++ b/Makefile
@@ -19,6 +19,7 @@ lint:
 test:
 	@TAIKO_MONO_DIR=${TAIKO_MONO_DIR} \
 	COMPILE_PROTOCOL=${COMPILE_PROTOCOL} \
+	PACKAGE=${PACKAGE} \
 	RUN_TESTS=true \
 		./integration_test/entrypoint.sh
 
diff --git a/pkg/chain_iterator/block_batch_iterator.go b/pkg/chain_iterator/block_batch_iterator.go
index fe72e566e..a8b192365 100644
--- a/pkg/chain_iterator/block_batch_iterator.go
+++ b/pkg/chain_iterator/block_batch_iterator.go
@@ -227,7 +227,7 @@ func (i *BlockBatchIterator) iter() (err error) {
 		return err
 	}
 
-	if err := i.onBlocks(i.ctx, i.current, endHeader, i.updateCurrent, i.rewindOnReorgDetected, i.end); err != nil {
+	if err := i.onBlocks(i.ctx, i.current, endHeader, i.updateCurrent, i.onReorg, i.end); err != nil {
 		return err
 	}
 
@@ -274,7 +274,7 @@ func (i *BlockBatchIterator) reverseIter() (err error) {
 		return err
 	}
 
-	if err := i.onBlocks(i.ctx, startHeader, i.current, i.updateCurrent, i.rewindOnReorgDetected, i.end); err != nil {
+	if err := i.onBlocks(i.ctx, startHeader, i.current, i.updateCurrent, i.onReorg, i.end); err != nil {
 		return err
 	}
 
diff --git a/pkg/chain_iterator/block_batch_iterator_test.go b/pkg/chain_iterator/block_batch_iterator_test.go
index 7c5d7de9e..4d0556f52 100644
--- a/pkg/chain_iterator/block_batch_iterator_test.go
+++ b/pkg/chain_iterator/block_batch_iterator_test.go
@@ -116,11 +116,11 @@ func (s *BlockBatchIteratorTestSuite) TestIterEndFunc() {
 	s.Equal(lastEnd.Uint64(), maxBlocksReadPerEpoch)
 }
 
-func (s *BlockBatchIteratorTestSuite) TestIter_ReorgEncounteredWithRemovedEvent() {
-	var maxBlocksReadPerEpoch uint64 = 2
+func (s *BlockBatchIteratorTestSuite) TestIter_ReorgEncountered() {
+	var maxBlocksReadPerEpoch uint64 = 1
 	var reorgRewindDepth uint64 = 1
-
-	var reorgedBlocks = 0
+	var reorgedBlocks uint64 = 0
+	var rewindEveryNBlocks uint64 = 2
 
 	headHeight, err := s.RpcClient.L1.BlockNumber(context.Background())
 	s.Nil(err)
@@ -136,7 +136,11 @@ func (s *BlockBatchIteratorTestSuite) TestIter_ReorgEncounteredWithRemovedEvent(
 		ReorgRewindDepth:      &reorgRewindDepth,
 		OnReorg: func() error {
 			reorgedBlocks++
-			lastEnd = new(big.Int).Sub(lastEnd, new(big.Int).SetUint64(reorgRewindDepth))
+			if lastEnd.Uint64() < reorgRewindDepth {
+				lastEnd = common.Big0
+			} else {
+				lastEnd = new(big.Int).Sub(lastEnd, new(big.Int).SetUint64(reorgRewindDepth))
+			}
 			return nil
 		},
 		OnBlocks: func(
@@ -146,12 +150,15 @@ func (s *BlockBatchIteratorTestSuite) TestIter_ReorgEncounteredWithRemovedEvent(
 			onReorgFunc OnReorgFunc,
 			endIterFunc EndIterFunc,
 		) error {
-			// reorg every 2 blocks
-			if end.Number.Uint64()%2 == 0 {
+			// reorg every 2 blocks but not the first block
+			if lastEnd != common.Big0 && end.Number.Uint64()%rewindEveryNBlocks == 0 {
 				return onReorgFunc()
 			}
 
-			s.Equal(lastEnd.Uint64(), start.Number.Uint64())
+			if lastEnd.Uint64() != 0 {
+				s.Equal(start.Number.Uint64(), lastEnd.Uint64()+rewindEveryNBlocks)
+			}
+
 			lastEnd = end.Number
 			return nil
 		},
@@ -159,8 +166,7 @@ func (s *BlockBatchIteratorTestSuite) TestIter_ReorgEncounteredWithRemovedEvent(
 
 	s.Nil(err)
 	s.Nil(iter.Iter())
-	s.Equal(headHeight, lastEnd.Uint64())
-	s.Equal(reorgedBlocks, (headHeight/2 - 1))
+	s.Equal((headHeight / rewindEveryNBlocks), reorgedBlocks)
 }
 
 func TestBlockBatchIteratorTestSuite(t *testing.T) {

From d530db83e5ff600922e2317543134784c321f3a9 Mon Sep 17 00:00:00 2001
From: Jeffery Walsh <cyberhorsey@gmail.com>
Date: Wed, 10 May 2023 17:49:10 -0700
Subject: [PATCH 08/25] abort handling blocks when reorg is detected

---
 pkg/chain_iterator/block_batch_iterator.go    | 19 +++++++++++++++----
 .../block_batch_iterator_test.go              | 18 +++++++++---------
 .../event_iterator/block_proposed_iterator.go | 14 +++++++-------
 .../event_iterator/block_proven_iterator.go   | 14 +++++++-------
 4 files changed, 38 insertions(+), 27 deletions(-)

diff --git a/pkg/chain_iterator/block_batch_iterator.go b/pkg/chain_iterator/block_batch_iterator.go
index a8b192365..a7d15c311 100644
--- a/pkg/chain_iterator/block_batch_iterator.go
+++ b/pkg/chain_iterator/block_batch_iterator.go
@@ -24,14 +24,14 @@ var (
 )
 
 // OnBlocksFunc represents the callback function which will be called when a batch of blocks in chain are
-// iterated.
+// iterated. It returns true if it reorged, and false if not.
 type OnBlocksFunc func(
 	ctx context.Context,
 	start, end *types.Header,
 	updateCurrentFunc UpdateCurrentFunc,
 	onReorgFunc OnReorgFunc,
 	endIterFunc EndIterFunc,
-) error
+) (bool, error)
 
 // UpdateCurrentFunc updates the iterator.current cursor in the iterator.
 type UpdateCurrentFunc func(*types.Header)
@@ -227,10 +227,16 @@ func (i *BlockBatchIterator) iter() (err error) {
 		return err
 	}
 
-	if err := i.onBlocks(i.ctx, i.current, endHeader, i.updateCurrent, i.onReorg, i.end); err != nil {
+	reorged, err := i.onBlocks(i.ctx, i.current, endHeader, i.updateCurrent, i.onReorg, i.end)
+	if err != nil {
 		return err
 	}
 
+	// if we reorged, we want to skip checking if we are at the end, and also skip updating i.current
+	if reorged {
+		return nil
+	}
+
 	if i.isEnd {
 		return io.EOF
 	}
@@ -274,10 +280,15 @@ func (i *BlockBatchIterator) reverseIter() (err error) {
 		return err
 	}
 
-	if err := i.onBlocks(i.ctx, startHeader, i.current, i.updateCurrent, i.onReorg, i.end); err != nil {
+	reorged, err := i.onBlocks(i.ctx, startHeader, i.current, i.updateCurrent, i.onReorg, i.end)
+	if err != nil {
 		return err
 	}
 
+	if reorged {
+		return nil
+	}
+
 	i.current = startHeader
 
 	if !isLastEpoch && !i.isEnd {
diff --git a/pkg/chain_iterator/block_batch_iterator_test.go b/pkg/chain_iterator/block_batch_iterator_test.go
index 4d0556f52..c49f7bc6f 100644
--- a/pkg/chain_iterator/block_batch_iterator_test.go
+++ b/pkg/chain_iterator/block_batch_iterator_test.go
@@ -35,10 +35,10 @@ func (s *BlockBatchIteratorTestSuite) TestIter() {
 			updateCurrentFunc UpdateCurrentFunc,
 			onReorgFunc OnReorgFunc,
 			endIterFunc EndIterFunc,
-		) error {
+		) (bool, error) {
 			s.Equal(lastEnd.Uint64(), start.Number.Uint64())
 			lastEnd = end.Number
-			return nil
+			return false, nil
 		},
 	})
 
@@ -71,10 +71,10 @@ func (s *BlockBatchIteratorTestSuite) TestIterReverse() {
 			updateCurrentFunc UpdateCurrentFunc,
 			onReorgFunc OnReorgFunc,
 			endIterFunc EndIterFunc,
-		) error {
+		) (bool, error) {
 			s.Equal(lastStart.Uint64(), end.Number.Uint64())
 			lastStart = start.Number
-			return nil
+			return false, nil
 		},
 	})
 
@@ -103,11 +103,11 @@ func (s *BlockBatchIteratorTestSuite) TestIterEndFunc() {
 			updateCurrentFunc UpdateCurrentFunc,
 			onReorgFunc OnReorgFunc,
 			endIterFunc EndIterFunc,
-		) error {
+		) (bool, error) {
 			s.Equal(lastEnd.Uint64(), start.Number.Uint64())
 			lastEnd = end.Number
 			endIterFunc()
-			return nil
+			return false, nil
 		},
 	})
 
@@ -149,10 +149,10 @@ func (s *BlockBatchIteratorTestSuite) TestIter_ReorgEncountered() {
 			updateCurrentFunc UpdateCurrentFunc,
 			onReorgFunc OnReorgFunc,
 			endIterFunc EndIterFunc,
-		) error {
+		) (bool, error) {
 			// reorg every 2 blocks but not the first block
 			if lastEnd != common.Big0 && end.Number.Uint64()%rewindEveryNBlocks == 0 {
-				return onReorgFunc()
+				return true, onReorgFunc()
 			}
 
 			if lastEnd.Uint64() != 0 {
@@ -160,7 +160,7 @@ func (s *BlockBatchIteratorTestSuite) TestIter_ReorgEncountered() {
 			}
 
 			lastEnd = end.Number
-			return nil
+			return false, nil
 		},
 	})
 
diff --git a/pkg/chain_iterator/event_iterator/block_proposed_iterator.go b/pkg/chain_iterator/event_iterator/block_proposed_iterator.go
index 74658e3c8..ff7b2bd69 100644
--- a/pkg/chain_iterator/event_iterator/block_proposed_iterator.go
+++ b/pkg/chain_iterator/event_iterator/block_proposed_iterator.go
@@ -107,14 +107,14 @@ func assembleBlockProposedIteratorCallback(
 		updateCurrentFunc chainIterator.UpdateCurrentFunc,
 		onReorgFunc chainIterator.OnReorgFunc,
 		endFunc chainIterator.EndIterFunc,
-	) error {
+	) (bool, error) {
 		endHeight := end.Number.Uint64()
 		iter, err := taikoL1Client.FilterBlockProposed(
 			&bind.FilterOpts{Start: start.Number.Uint64(), End: &endHeight, Context: ctx},
 			filterQuery,
 		)
 		if err != nil {
-			return err
+			return false, err
 		}
 		defer iter.Close()
 
@@ -122,26 +122,26 @@ func assembleBlockProposedIteratorCallback(
 			event := iter.Event
 
 			if event.Raw.Removed {
-				return onReorgFunc()
+				return true, onReorgFunc()
 			}
 
 			if err := callback(ctx, event, eventIter.end); err != nil {
-				return err
+				return false, err
 			}
 
 			if eventIter.isEnd {
 				endFunc()
-				return nil
+				return false, nil
 			}
 
 			current, err := client.HeaderByHash(ctx, event.Raw.BlockHash)
 			if err != nil {
-				return err
+				return false, err
 			}
 
 			updateCurrentFunc(current)
 		}
 
-		return nil
+		return false, nil
 	}
 }
diff --git a/pkg/chain_iterator/event_iterator/block_proven_iterator.go b/pkg/chain_iterator/event_iterator/block_proven_iterator.go
index 8228c39e6..43b4f5f12 100644
--- a/pkg/chain_iterator/event_iterator/block_proven_iterator.go
+++ b/pkg/chain_iterator/event_iterator/block_proven_iterator.go
@@ -103,14 +103,14 @@ func assembleBlockProvenIteratorCallback(
 		updateCurrentFunc chainIterator.UpdateCurrentFunc,
 		onReorgFunc chainIterator.OnReorgFunc,
 		endFunc chainIterator.EndIterFunc,
-	) error {
+	) (bool, error) {
 		endHeight := end.Number.Uint64()
 		iter, err := taikoL1Client.FilterBlockProven(
 			&bind.FilterOpts{Start: start.Number.Uint64(), End: &endHeight, Context: ctx},
 			filterQuery,
 		)
 		if err != nil {
-			return err
+			return false, err
 		}
 		defer iter.Close()
 
@@ -118,26 +118,26 @@ func assembleBlockProvenIteratorCallback(
 			event := iter.Event
 
 			if event.Raw.Removed {
-				return onReorgFunc()
+				return true, onReorgFunc()
 			}
 
 			if err := callback(ctx, event, eventIter.end); err != nil {
-				return err
+				return false, err
 			}
 
 			if eventIter.isEnd {
 				endFunc()
-				return nil
+				return false, nil
 			}
 
 			current, err := client.HeaderByHash(ctx, event.Raw.BlockHash)
 			if err != nil {
-				return err
+				return false, err
 			}
 
 			updateCurrentFunc(current)
 		}
 
-		return nil
+		return false, nil
 	}
 }

From 42baf918c2ff46ffe72735d2e13a035da51c7122 Mon Sep 17 00:00:00 2001
From: Jeffery Walsh <cyberhorsey@gmail.com>
Date: Wed, 10 May 2023 18:12:36 -0700
Subject: [PATCH 09/25] tests

---
 pkg/chain_iterator/block_batch_iterator_test.go | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/pkg/chain_iterator/block_batch_iterator_test.go b/pkg/chain_iterator/block_batch_iterator_test.go
index c49f7bc6f..7a2af0d98 100644
--- a/pkg/chain_iterator/block_batch_iterator_test.go
+++ b/pkg/chain_iterator/block_batch_iterator_test.go
@@ -2,6 +2,7 @@ package chainiterator
 
 import (
 	"context"
+	"fmt"
 	"math/big"
 	"testing"
 
@@ -121,6 +122,7 @@ func (s *BlockBatchIteratorTestSuite) TestIter_ReorgEncountered() {
 	var reorgRewindDepth uint64 = 1
 	var reorgedBlocks uint64 = 0
 	var rewindEveryNBlocks uint64 = 2
+	var lastBlockReorged bool = false
 
 	headHeight, err := s.RpcClient.L1.BlockNumber(context.Background())
 	s.Nil(err)
@@ -135,12 +137,14 @@ func (s *BlockBatchIteratorTestSuite) TestIter_ReorgEncountered() {
 		EndHeight:             new(big.Int).SetUint64(headHeight),
 		ReorgRewindDepth:      &reorgRewindDepth,
 		OnReorg: func() error {
+			fmt.Println("reorging", lastEnd.Uint64())
 			reorgedBlocks++
 			if lastEnd.Uint64() < reorgRewindDepth {
 				lastEnd = common.Big0
 			} else {
 				lastEnd = new(big.Int).Sub(lastEnd, new(big.Int).SetUint64(reorgRewindDepth))
 			}
+			lastBlockReorged = true
 			return nil
 		},
 		OnBlocks: func(
@@ -151,15 +155,20 @@ func (s *BlockBatchIteratorTestSuite) TestIter_ReorgEncountered() {
 			endIterFunc EndIterFunc,
 		) (bool, error) {
 			// reorg every 2 blocks but not the first block
-			if lastEnd != common.Big0 && end.Number.Uint64()%rewindEveryNBlocks == 0 {
+			if lastEnd != common.Big0 && lastEnd.Uint64()%rewindEveryNBlocks == 0 {
 				return true, onReorgFunc()
 			}
 
-			if lastEnd.Uint64() != 0 {
-				s.Equal(start.Number.Uint64(), lastEnd.Uint64()+rewindEveryNBlocks)
+			fmt.Println("not reorging: ", "start", start.Number.Int64(), "lastEnd", lastEnd.Uint64(), "end", end.Number.Uint64())
+
+			if lastBlockReorged {
+				s.Equal(start.Number.Uint64(), lastEnd.Uint64()+reorgRewindDepth)
+			} else {
+
 			}
 
 			lastEnd = end.Number
+			lastBlockReorged = false
 			return false, nil
 		},
 	})

From 4865f1fd32329ac3e1e4435fc7d9590de3dca1f0 Mon Sep 17 00:00:00 2001
From: Jeffery Walsh <cyberhorsey@gmail.com>
Date: Wed, 10 May 2023 18:12:46 -0700
Subject: [PATCH 10/25] comment

---
 pkg/chain_iterator/block_batch_iterator_test.go | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/pkg/chain_iterator/block_batch_iterator_test.go b/pkg/chain_iterator/block_batch_iterator_test.go
index 7a2af0d98..dc306a1ea 100644
--- a/pkg/chain_iterator/block_batch_iterator_test.go
+++ b/pkg/chain_iterator/block_batch_iterator_test.go
@@ -2,7 +2,6 @@ package chainiterator
 
 import (
 	"context"
-	"fmt"
 	"math/big"
 	"testing"
 
@@ -137,7 +136,6 @@ func (s *BlockBatchIteratorTestSuite) TestIter_ReorgEncountered() {
 		EndHeight:             new(big.Int).SetUint64(headHeight),
 		ReorgRewindDepth:      &reorgRewindDepth,
 		OnReorg: func() error {
-			fmt.Println("reorging", lastEnd.Uint64())
 			reorgedBlocks++
 			if lastEnd.Uint64() < reorgRewindDepth {
 				lastEnd = common.Big0
@@ -159,8 +157,6 @@ func (s *BlockBatchIteratorTestSuite) TestIter_ReorgEncountered() {
 				return true, onReorgFunc()
 			}
 
-			fmt.Println("not reorging: ", "start", start.Number.Int64(), "lastEnd", lastEnd.Uint64(), "end", end.Number.Uint64())
-
 			if lastBlockReorged {
 				s.Equal(start.Number.Uint64(), lastEnd.Uint64()+reorgRewindDepth)
 			} else {

From 75d4919ce401690a086509f6cc9a2fcd3e796346 Mon Sep 17 00:00:00 2001
From: Jeffery Walsh <cyberhorsey@gmail.com>
Date: Wed, 10 May 2023 18:20:12 -0700
Subject: [PATCH 11/25] tests

---
 pkg/chain_iterator/block_batch_iterator_test.go | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/pkg/chain_iterator/block_batch_iterator_test.go b/pkg/chain_iterator/block_batch_iterator_test.go
index dc306a1ea..ebb243cae 100644
--- a/pkg/chain_iterator/block_batch_iterator_test.go
+++ b/pkg/chain_iterator/block_batch_iterator_test.go
@@ -119,7 +119,6 @@ func (s *BlockBatchIteratorTestSuite) TestIterEndFunc() {
 func (s *BlockBatchIteratorTestSuite) TestIter_ReorgEncountered() {
 	var maxBlocksReadPerEpoch uint64 = 1
 	var reorgRewindDepth uint64 = 1
-	var reorgedBlocks uint64 = 0
 	var rewindEveryNBlocks uint64 = 2
 	var lastBlockReorged bool = false
 
@@ -136,7 +135,6 @@ func (s *BlockBatchIteratorTestSuite) TestIter_ReorgEncountered() {
 		EndHeight:             new(big.Int).SetUint64(headHeight),
 		ReorgRewindDepth:      &reorgRewindDepth,
 		OnReorg: func() error {
-			reorgedBlocks++
 			if lastEnd.Uint64() < reorgRewindDepth {
 				lastEnd = common.Big0
 			} else {
@@ -160,7 +158,7 @@ func (s *BlockBatchIteratorTestSuite) TestIter_ReorgEncountered() {
 			if lastBlockReorged {
 				s.Equal(start.Number.Uint64(), lastEnd.Uint64()+reorgRewindDepth)
 			} else {
-
+				s.Equal(start.Number.Uint64(), lastEnd.Uint64())
 			}
 
 			lastEnd = end.Number
@@ -171,7 +169,6 @@ func (s *BlockBatchIteratorTestSuite) TestIter_ReorgEncountered() {
 
 	s.Nil(err)
 	s.Nil(iter.Iter())
-	s.Equal((headHeight / rewindEveryNBlocks), reorgedBlocks)
 }
 
 func TestBlockBatchIteratorTestSuite(t *testing.T) {

From 882f29ffacce4a654fc37cdd93ea7928040f70d8 Mon Sep 17 00:00:00 2001
From: Jeffery Walsh <cyberhorsey@gmail.com>
Date: Thu, 11 May 2023 18:33:16 -0700
Subject: [PATCH 12/25] comments

---
 driver/chain_syncer/calldata/syncer.go | 117 +++++++++++++++++++++++++
 1 file changed, 117 insertions(+)

diff --git a/driver/chain_syncer/calldata/syncer.go b/driver/chain_syncer/calldata/syncer.go
index cc165d1ce..d7b07ef91 100644
--- a/driver/chain_syncer/calldata/syncer.go
+++ b/driver/chain_syncer/calldata/syncer.go
@@ -7,6 +7,7 @@ import (
 	"math/big"
 	"time"
 
+	"github.com/ethereum/go-ethereum"
 	"github.com/ethereum/go-ethereum/accounts/abi/bind"
 	"github.com/ethereum/go-ethereum/beacon/engine"
 	"github.com/ethereum/go-ethereum/common"
@@ -114,8 +115,14 @@ func (s *Syncer) onBlockProposed(
 		"L1Height", event.Raw.BlockNumber,
 		"L1Hash", event.Raw.BlockHash,
 		"BlockID", event.Id,
+		"Removed", event.Raw.Removed,
 	)
 
+	// handle reorg
+	if event.Raw.Removed {
+		return s.handleReorg(ctx, event)
+	}
+
 	// Fetch the L2 parent block.
 	var (
 		parent *types.Header
@@ -223,6 +230,116 @@ func (s *Syncer) onBlockProposed(
 	return nil
 }
 
+// handleReorg detects reorg and rewinds the chain by 1 until we find a block that is still in the chain,
+// then inserts that chain as the new head.
+func (s *Syncer) handleReorg(ctx context.Context, event *bindings.TaikoL1ClientBlockProposed) error {
+	log.Info(
+		"Reorg detected",
+		"L1Height", event.Raw.BlockNumber,
+		"L1Hash", event.Raw.BlockHash,
+		"BlockID", event.Id,
+		"Removed", event.Raw.Removed,
+	)
+
+	// rewind chain by 1 until we find a block that is still in the chain
+	var lastKnownGoodBlockId *big.Int
+	var blockId *big.Int = s.lastInsertedBlockID
+
+	for lastKnownGoodBlockId == nil {
+		block, err := s.rpc.L2.BlockByNumber(ctx, blockId)
+		if err != nil && !errors.Is(err, ethereum.NotFound) {
+			return err
+		}
+
+		if block != nil {
+			// block exists, we can rewind to this block
+			lastKnownGoodBlockId = blockId
+		} else {
+			// otherwise, sub 1 from blockId and try again
+			blockId = new(big.Int).Sub(s.lastInsertedBlockID, big.NewInt(1))
+		}
+	}
+
+	log.Info(
+		"🔗 Last known good block ID before reorg found",
+		"blockID", event.Id,
+	)
+
+	parent, err := s.rpc.L2ParentByBlockId(ctx, lastKnownGoodBlockId)
+	if err != nil {
+		return fmt.Errorf("error getting l2 parent by block id: %w", err)
+	}
+
+	tx, err := s.rpc.L1.TransactionInBlock(
+		ctx,
+		event.Raw.BlockHash,
+		event.Raw.TxIndex,
+	)
+	if err != nil {
+		return fmt.Errorf("failed to fetch original TaikoL1.proposeBlock transaction: %w", err)
+	}
+
+	txListBytes, hint, _, err := s.txListValidator.ValidateTxList(event.Id, tx.Data())
+	if err != nil {
+		return fmt.Errorf("failed to validate transactions list: %w", err)
+	}
+
+	if hint != txListValidator.HintOK {
+		log.Info("Invalid transactions list, insert an empty L2 block instead", "blockID", event.Id)
+		txListBytes = []byte{}
+	}
+
+	l1Origin := &rawdb.L1Origin{
+		BlockID:       event.Id,
+		L2BlockHash:   common.Hash{}, // Will be set by taiko-geth.
+		L1BlockHeight: new(big.Int).SetUint64(event.Raw.BlockNumber),
+		L1BlockHash:   event.Raw.BlockHash,
+	}
+
+	payloadData, rpcError, payloadError := s.insertNewHead(
+		ctx,
+		event,
+		parent,
+		s.state.GetHeadBlockID(),
+		txListBytes,
+		l1Origin,
+	)
+
+	if rpcError != nil {
+		return fmt.Errorf("failed to insert new head to L2 execution engine: %w", rpcError)
+	}
+
+	if payloadError != nil {
+		log.Warn(
+			"Ignore invalid block context", "blockID", event.Id, "payloadError", payloadError, "payloadData", payloadData,
+		)
+		return nil
+	}
+
+	log.Debug("Payload data", "hash", payloadData.BlockHash, "txs", len(payloadData.Transactions))
+
+	log.Info(
+		"🔗 Rewound chain and inserted last known good block as new head",
+		"blockID", event.Id,
+		"height", payloadData.Number,
+		"hash", payloadData.BlockHash,
+		"latestVerifiedBlockHeight", s.state.GetLatestVerifiedBlock().Height,
+		"latestVerifiedBlockHash", s.state.GetLatestVerifiedBlock().Hash,
+		"transactions", len(payloadData.Transactions),
+		"baseFee", payloadData.BaseFeePerGas,
+		"withdrawals", len(payloadData.Withdrawals),
+	)
+
+	metrics.DriverL1CurrentHeightGauge.Update(int64(event.Raw.BlockNumber))
+	s.lastInsertedBlockID = event.Id
+
+	if s.progressTracker.Triggered() {
+		s.progressTracker.ClearMeta()
+	}
+
+	return nil
+}
+
 // insertNewHead tries to insert a new head block to the L2 execution engine's local
 // block chain through Engine APIs.
 func (s *Syncer) insertNewHead(

From 16711a3568ab0173f5009a76ef04144eaf3b2a86 Mon Sep 17 00:00:00 2001
From: Jeffery Walsh <cyberhorsey@gmail.com>
Date: Thu, 11 May 2023 18:34:00 -0700
Subject: [PATCH 13/25] detect if block id is 0

---
 driver/chain_syncer/calldata/syncer.go | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/driver/chain_syncer/calldata/syncer.go b/driver/chain_syncer/calldata/syncer.go
index d7b07ef91..3a250cee1 100644
--- a/driver/chain_syncer/calldata/syncer.go
+++ b/driver/chain_syncer/calldata/syncer.go
@@ -246,6 +246,11 @@ func (s *Syncer) handleReorg(ctx context.Context, event *bindings.TaikoL1ClientB
 	var blockId *big.Int = s.lastInsertedBlockID
 
 	for lastKnownGoodBlockId == nil {
+		if blockId.Cmp(big.NewInt(0)) == 0 {
+			lastKnownGoodBlockId = new(big.Int).SetUint64(0)
+			break
+		}
+
 		block, err := s.rpc.L2.BlockByNumber(ctx, blockId)
 		if err != nil && !errors.Is(err, ethereum.NotFound) {
 			return err

From 6e76e34d671c666158f08c754c6b2b2c74967093 Mon Sep 17 00:00:00 2001
From: Jeffery Walsh <cyberhorsey@gmail.com>
Date: Thu, 11 May 2023 19:44:05 -0700
Subject: [PATCH 14/25] reset l1 current + get event

---
 driver/chain_syncer/calldata/syncer.go | 37 ++++++++++++++++++--------
 driver/chain_syncer/chain_syncer.go    |  2 +-
 driver/state/l1_current.go             | 36 ++++++++++++-------------
 3 files changed, 45 insertions(+), 30 deletions(-)

diff --git a/driver/chain_syncer/calldata/syncer.go b/driver/chain_syncer/calldata/syncer.go
index 3a250cee1..ef56fac14 100644
--- a/driver/chain_syncer/calldata/syncer.go
+++ b/driver/chain_syncer/calldata/syncer.go
@@ -244,14 +244,16 @@ func (s *Syncer) handleReorg(ctx context.Context, event *bindings.TaikoL1ClientB
 	// rewind chain by 1 until we find a block that is still in the chain
 	var lastKnownGoodBlockId *big.Int
 	var blockId *big.Int = s.lastInsertedBlockID
+	var block *types.Block
+	var err error
 
-	for lastKnownGoodBlockId == nil {
+	for {
 		if blockId.Cmp(big.NewInt(0)) == 0 {
 			lastKnownGoodBlockId = new(big.Int).SetUint64(0)
 			break
 		}
 
-		block, err := s.rpc.L2.BlockByNumber(ctx, blockId)
+		block, err = s.rpc.L2.BlockByNumber(ctx, blockId)
 		if err != nil && !errors.Is(err, ethereum.NotFound) {
 			return err
 		}
@@ -259,12 +261,19 @@ func (s *Syncer) handleReorg(ctx context.Context, event *bindings.TaikoL1ClientB
 		if block != nil {
 			// block exists, we can rewind to this block
 			lastKnownGoodBlockId = blockId
+			break
 		} else {
 			// otherwise, sub 1 from blockId and try again
 			blockId = new(big.Int).Sub(s.lastInsertedBlockID, big.NewInt(1))
 		}
 	}
 
+	// shouuldnt be able to reach this error because of the 0 check above
+	// but just in case
+	if lastKnownGoodBlockId == nil {
+		return fmt.Errorf("failed to find last known good block ID after reorg")
+	}
+
 	log.Info(
 		"🔗 Last known good block ID before reorg found",
 		"blockID", event.Id,
@@ -275,35 +284,41 @@ func (s *Syncer) handleReorg(ctx context.Context, event *bindings.TaikoL1ClientB
 		return fmt.Errorf("error getting l2 parent by block id: %w", err)
 	}
 
+	// reset l1 current to when the last known good block was inserted, and return the event.
+	blockProposedEvent, _, err := s.state.ResetL1Current(ctx, &state.HeightOrID{Height: block.Number()})
+	if err != nil {
+		return fmt.Errorf("faile to reset l1 current: %w", err)
+	}
+
 	tx, err := s.rpc.L1.TransactionInBlock(
 		ctx,
-		event.Raw.BlockHash,
-		event.Raw.TxIndex,
+		block.Hash(),
+		blockProposedEvent.Raw.TxIndex,
 	)
 	if err != nil {
 		return fmt.Errorf("failed to fetch original TaikoL1.proposeBlock transaction: %w", err)
 	}
 
-	txListBytes, hint, _, err := s.txListValidator.ValidateTxList(event.Id, tx.Data())
+	txListBytes, hint, _, err := s.txListValidator.ValidateTxList(block.Number(), tx.Data())
 	if err != nil {
 		return fmt.Errorf("failed to validate transactions list: %w", err)
 	}
 
 	if hint != txListValidator.HintOK {
-		log.Info("Invalid transactions list, insert an empty L2 block instead", "blockID", event.Id)
+		log.Info("Invalid transactions list, insert an empty L2 block instead", "blockID", block.NumberU64())
 		txListBytes = []byte{}
 	}
 
 	l1Origin := &rawdb.L1Origin{
-		BlockID:       event.Id,
+		BlockID:       block.Number(),
 		L2BlockHash:   common.Hash{}, // Will be set by taiko-geth.
-		L1BlockHeight: new(big.Int).SetUint64(event.Raw.BlockNumber),
-		L1BlockHash:   event.Raw.BlockHash,
+		L1BlockHeight: new(big.Int).SetUint64(blockProposedEvent.Raw.BlockNumber),
+		L1BlockHash:   blockProposedEvent.Raw.BlockHash,
 	}
 
 	payloadData, rpcError, payloadError := s.insertNewHead(
 		ctx,
-		event,
+		blockProposedEvent,
 		parent,
 		s.state.GetHeadBlockID(),
 		txListBytes,
@@ -336,7 +351,7 @@ func (s *Syncer) handleReorg(ctx context.Context, event *bindings.TaikoL1ClientB
 	)
 
 	metrics.DriverL1CurrentHeightGauge.Update(int64(event.Raw.BlockNumber))
-	s.lastInsertedBlockID = event.Id
+	s.lastInsertedBlockID = block.Number()
 
 	if s.progressTracker.Triggered() {
 		s.progressTracker.ClearMeta()
diff --git a/driver/chain_syncer/chain_syncer.go b/driver/chain_syncer/chain_syncer.go
index 268198970..798299433 100644
--- a/driver/chain_syncer/chain_syncer.go
+++ b/driver/chain_syncer/chain_syncer.go
@@ -119,7 +119,7 @@ func (s *L2ChainSyncer) Sync(l1End *types.Header) error {
 		}
 
 		// Reset the L1Current cursor.
-		blockID, err := s.state.ResetL1Current(s.ctx, heightOrID)
+		_, blockID, err := s.state.ResetL1Current(s.ctx, heightOrID)
 		if err != nil {
 			return err
 		}
diff --git a/driver/state/l1_current.go b/driver/state/l1_current.go
index 5cf3f7956..b0a501790 100644
--- a/driver/state/l1_current.go
+++ b/driver/state/l1_current.go
@@ -29,33 +29,32 @@ func (s *State) SetL1Current(h *types.Header) {
 
 // ResetL1Current resets the l1Current cursor to the L1 height which emitted a
 // BlockProven event with given blockID / blockHash.
-func (s *State) ResetL1Current(ctx context.Context, heightOrID *HeightOrID) (*big.Int, error) {
+func (s *State) ResetL1Current(ctx context.Context, heightOrID *HeightOrID) (*bindings.TaikoL1ClientBlockProposed, *big.Int, error) {
 	if !heightOrID.NotEmpty() {
-		return nil, fmt.Errorf("empty input %v", heightOrID)
+		return nil, nil, fmt.Errorf("empty input %v", heightOrID)
 	}
 
 	log.Info("Reset L1 current cursor", "heightOrID", heightOrID)
 
 	var (
-		l1CurrentHeight *big.Int
-		err             error
+		err error
 	)
 
 	if (heightOrID.ID != nil && heightOrID.ID.Cmp(common.Big0) == 0) ||
 		(heightOrID.Height != nil && heightOrID.Height.Cmp(common.Big0) == 0) {
 		l1Current, err := s.rpc.L1.HeaderByNumber(ctx, s.GenesisL1Height)
 		if err != nil {
-			return nil, err
+			return nil, nil, err
 		}
 		s.SetL1Current(l1Current)
-		return common.Big0, nil
+		return nil, common.Big0, nil
 	}
 
 	// Need to find the block ID at first, before filtering the BlockProposed events.
 	if heightOrID.ID == nil {
 		header, err := s.rpc.L2.HeaderByNumber(context.Background(), heightOrID.Height)
 		if err != nil {
-			return nil, err
+			return nil, nil, err
 		}
 		targetHash := header.Hash()
 
@@ -85,18 +84,19 @@ func (s *State) ResetL1Current(ctx context.Context, heightOrID *HeightOrID) (*bi
 		)
 
 		if err != nil {
-			return nil, err
+			return nil, nil, err
 		}
 
 		if err := iter.Iter(); err != nil {
-			return nil, err
+			return nil, nil, err
 		}
 
 		if heightOrID.ID == nil {
-			return nil, fmt.Errorf("BlockProven event not found, hash: %s", targetHash)
+			return nil, nil, fmt.Errorf("BlockProven event not found, hash: %s", targetHash)
 		}
 	}
 
+	var event *bindings.TaikoL1ClientBlockProposed
 	iter, err := eventIterator.NewBlockProposedIterator(
 		ctx,
 		&eventIterator.BlockProposedIteratorConfig{
@@ -111,7 +111,7 @@ func (s *State) ResetL1Current(ctx context.Context, heightOrID *HeightOrID) (*bi
 				e *bindings.TaikoL1ClientBlockProposed,
 				end eventIterator.EndBlockProposedEventIterFunc,
 			) error {
-				l1CurrentHeight = new(big.Int).SetUint64(e.Raw.BlockNumber)
+				event = e
 				end()
 				return nil
 			},
@@ -119,24 +119,24 @@ func (s *State) ResetL1Current(ctx context.Context, heightOrID *HeightOrID) (*bi
 	)
 
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 
 	if err := iter.Iter(); err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 
-	if l1CurrentHeight == nil {
-		return nil, fmt.Errorf("BlockProposed event not found, blockID: %s", heightOrID.ID)
+	if event == nil {
+		return nil, nil, fmt.Errorf("BlockProposed event not found, blockID: %s", heightOrID.ID)
 	}
 
-	l1Current, err := s.rpc.L1.HeaderByNumber(ctx, l1CurrentHeight)
+	l1Current, err := s.rpc.L1.HeaderByNumber(ctx, new(big.Int).SetUint64(event.Raw.BlockNumber))
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 	s.SetL1Current(l1Current)
 
 	log.Info("Reset L1 current cursor", "height", s.GetL1Current().Number)
 
-	return heightOrID.ID, nil
+	return event, heightOrID.ID, nil
 }

From 2d4f88c163c18080e8403daa73d6799e4b3af27c Mon Sep 17 00:00:00 2001
From: Jeffery Walsh <cyberhorsey@gmail.com>
Date: Thu, 11 May 2023 19:44:31 -0700
Subject: [PATCH 15/25] tests

---
 driver/state/l1_current_test.go | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/driver/state/l1_current_test.go b/driver/state/l1_current_test.go
index 31367cb3e..86b26b60d 100644
--- a/driver/state/l1_current_test.go
+++ b/driver/state/l1_current_test.go
@@ -19,15 +19,15 @@ func (s *DriverStateTestSuite) TestSetL1Current() {
 }
 
 func (s *DriverStateTestSuite) TestResetL1CurrentEmptyHeight() {
-	l1Current, err := s.s.ResetL1Current(context.Background(), &HeightOrID{ID: common.Big0})
+	_, l1Current, err := s.s.ResetL1Current(context.Background(), &HeightOrID{ID: common.Big0})
 	s.Nil(err)
 	s.Zero(l1Current.Uint64())
 
-	_, err = s.s.ResetL1Current(context.Background(), &HeightOrID{Height: common.Big0})
+	_, _, err = s.s.ResetL1Current(context.Background(), &HeightOrID{Height: common.Big0})
 	s.Nil(err)
 }
 
 func (s *DriverStateTestSuite) TestResetL1CurrentEmptyID() {
-	_, err := s.s.ResetL1Current(context.Background(), &HeightOrID{Height: common.Big1})
+	_, _, err := s.s.ResetL1Current(context.Background(), &HeightOrID{Height: common.Big1})
 	s.NotNil(err)
 }

From bd8b1c93e5c91788716e7a39729be0078cfeae23 Mon Sep 17 00:00:00 2001
From: Jeffery Walsh <cyberhorsey@gmail.com>
Date: Thu, 11 May 2023 19:56:27 -0700
Subject: [PATCH 16/25] lint

---
 driver/state/l1_current.go | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/driver/state/l1_current.go b/driver/state/l1_current.go
index b0a501790..9fa016801 100644
--- a/driver/state/l1_current.go
+++ b/driver/state/l1_current.go
@@ -29,7 +29,10 @@ func (s *State) SetL1Current(h *types.Header) {
 
 // ResetL1Current resets the l1Current cursor to the L1 height which emitted a
 // BlockProven event with given blockID / blockHash.
-func (s *State) ResetL1Current(ctx context.Context, heightOrID *HeightOrID) (*bindings.TaikoL1ClientBlockProposed, *big.Int, error) {
+func (s *State) ResetL1Current(
+	ctx context.Context,
+	heightOrID *HeightOrID,
+) (*bindings.TaikoL1ClientBlockProposed, *big.Int, error) {
 	if !heightOrID.NotEmpty() {
 		return nil, nil, fmt.Errorf("empty input %v", heightOrID)
 	}

From 5910819c19143a54c298d4143908ef455e5e6bda Mon Sep 17 00:00:00 2001
From: Jeffery Walsh <cyberhorsey@gmail.com>
Date: Thu, 11 May 2023 19:57:47 -0700
Subject: [PATCH 17/25] comment was incorrect, i belive ResetL1Current is for
 blockProposed, not blockProven

---
 driver/state/l1_current.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/driver/state/l1_current.go b/driver/state/l1_current.go
index 9fa016801..e9eb90f94 100644
--- a/driver/state/l1_current.go
+++ b/driver/state/l1_current.go
@@ -28,7 +28,7 @@ func (s *State) SetL1Current(h *types.Header) {
 }
 
 // ResetL1Current resets the l1Current cursor to the L1 height which emitted a
-// BlockProven event with given blockID / blockHash.
+// BlockProposed event with given blockID / blockHash.
 func (s *State) ResetL1Current(
 	ctx context.Context,
 	heightOrID *HeightOrID,

From d9db02d420333a0dc58adcfe8c2baaede4c71b6a Mon Sep 17 00:00:00 2001
From: jeff <113397187+cyberhorsey@users.noreply.github.com>
Date: Mon, 15 May 2023 11:14:42 -0700
Subject: [PATCH 18/25] Update driver/chain_syncer/calldata/syncer.go

Co-authored-by: David <david@taiko.xyz>
---
 driver/chain_syncer/calldata/syncer.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/driver/chain_syncer/calldata/syncer.go b/driver/chain_syncer/calldata/syncer.go
index ef56fac14..e1ebec2a7 100644
--- a/driver/chain_syncer/calldata/syncer.go
+++ b/driver/chain_syncer/calldata/syncer.go
@@ -231,7 +231,7 @@ func (s *Syncer) onBlockProposed(
 }
 
 // handleReorg detects reorg and rewinds the chain by 1 until we find a block that is still in the chain,
-// then inserts that chain as the new head.
+// then inserts that block as the new head.
 func (s *Syncer) handleReorg(ctx context.Context, event *bindings.TaikoL1ClientBlockProposed) error {
 	log.Info(
 		"Reorg detected",

From e63464491d342657453d37b8533c2e8ac4e41107 Mon Sep 17 00:00:00 2001
From: jeff <113397187+cyberhorsey@users.noreply.github.com>
Date: Mon, 15 May 2023 11:14:50 -0700
Subject: [PATCH 19/25] Update driver/chain_syncer/calldata/syncer.go

Co-authored-by: David <david@taiko.xyz>
---
 driver/chain_syncer/calldata/syncer.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/driver/chain_syncer/calldata/syncer.go b/driver/chain_syncer/calldata/syncer.go
index e1ebec2a7..36f71ca5b 100644
--- a/driver/chain_syncer/calldata/syncer.go
+++ b/driver/chain_syncer/calldata/syncer.go
@@ -268,7 +268,7 @@ func (s *Syncer) handleReorg(ctx context.Context, event *bindings.TaikoL1ClientB
 		}
 	}
 
-	// shouuldnt be able to reach this error because of the 0 check above
+	// shouldn't be able to reach this error because of the 0 check above
 	// but just in case
 	if lastKnownGoodBlockId == nil {
 		return fmt.Errorf("failed to find last known good block ID after reorg")

From b00ac3941b420de3d2d8b6f671ae9bb9a8c1cd54 Mon Sep 17 00:00:00 2001
From: jeff <113397187+cyberhorsey@users.noreply.github.com>
Date: Mon, 15 May 2023 11:15:01 -0700
Subject: [PATCH 20/25] Update driver/chain_syncer/calldata/syncer.go

Co-authored-by: David <david@taiko.xyz>
---
 driver/chain_syncer/calldata/syncer.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/driver/chain_syncer/calldata/syncer.go b/driver/chain_syncer/calldata/syncer.go
index 36f71ca5b..0140014a2 100644
--- a/driver/chain_syncer/calldata/syncer.go
+++ b/driver/chain_syncer/calldata/syncer.go
@@ -287,7 +287,7 @@ func (s *Syncer) handleReorg(ctx context.Context, event *bindings.TaikoL1ClientB
 	// reset l1 current to when the last known good block was inserted, and return the event.
 	blockProposedEvent, _, err := s.state.ResetL1Current(ctx, &state.HeightOrID{Height: block.Number()})
 	if err != nil {
-		return fmt.Errorf("faile to reset l1 current: %w", err)
+		return fmt.Errorf("failed to reset l1 current: %w", err)
 	}
 
 	tx, err := s.rpc.L1.TransactionInBlock(

From 092c717d178a07b0bb28d81bd3ca65a739bc336b Mon Sep 17 00:00:00 2001
From: Jeffery Walsh <cyberhorsey@gmail.com>
Date: Mon, 15 May 2023 12:05:57 -0700
Subject: [PATCH 21/25] compare to state vars num blocks, and handle 0 block
 for rewinding

---
 driver/chain_syncer/calldata/syncer.go      | 69 +++++++++++++++------
 driver/chain_syncer/calldata/syncer_test.go |  6 +-
 2 files changed, 56 insertions(+), 19 deletions(-)

diff --git a/driver/chain_syncer/calldata/syncer.go b/driver/chain_syncer/calldata/syncer.go
index 0140014a2..7a08493b9 100644
--- a/driver/chain_syncer/calldata/syncer.go
+++ b/driver/chain_syncer/calldata/syncer.go
@@ -26,6 +26,14 @@ import (
 	txListValidator "github.com/taikoxyz/taiko-client/pkg/tx_list_validator"
 )
 
+// ParentBlockInfo is an abstraction between *types.Header and our code, to allow passing in
+// a zero hash and other zero-value fields.
+type ParentBlockInfo struct {
+	Hash    common.Hash
+	Number  *big.Int
+	GasUsed uint64
+}
+
 // Syncer responsible for letting the L2 execution engine catching up with protocol's latest
 // pending block through deriving L1 calldata.
 type Syncer struct {
@@ -188,7 +196,11 @@ func (s *Syncer) onBlockProposed(
 	payloadData, rpcError, payloadError := s.insertNewHead(
 		ctx,
 		event,
-		parent,
+		&ParentBlockInfo{
+			Hash:    parent.Hash(),
+			Number:  parent.Number,
+			GasUsed: parent.GasUsed,
+		},
 		s.state.GetHeadBlockID(),
 		txListBytes,
 		l1Origin,
@@ -247,6 +259,11 @@ func (s *Syncer) handleReorg(ctx context.Context, event *bindings.TaikoL1ClientB
 	var block *types.Block
 	var err error
 
+	stateVars, err := s.rpc.GetProtocolStateVariables()
+	if err != nil {
+		return fmt.Errorf("failed to get state variables: %w", err)
+	}
+
 	for {
 		if blockId.Cmp(big.NewInt(0)) == 0 {
 			lastKnownGoodBlockId = new(big.Int).SetUint64(0)
@@ -258,7 +275,7 @@ func (s *Syncer) handleReorg(ctx context.Context, event *bindings.TaikoL1ClientB
 			return err
 		}
 
-		if block != nil {
+		if block != nil && blockId.Uint64() < stateVars.NumBlocks {
 			// block exists, we can rewind to this block
 			lastKnownGoodBlockId = blockId
 			break
@@ -276,12 +293,28 @@ func (s *Syncer) handleReorg(ctx context.Context, event *bindings.TaikoL1ClientB
 
 	log.Info(
 		"🔗 Last known good block ID before reorg found",
-		"blockID", event.Id,
+		"blockID", lastKnownGoodBlockId,
 	)
 
-	parent, err := s.rpc.L2ParentByBlockId(ctx, lastKnownGoodBlockId)
-	if err != nil {
-		return fmt.Errorf("error getting l2 parent by block id: %w", err)
+	var parentBlockInfo *ParentBlockInfo
+
+	if lastKnownGoodBlockId.Cmp(common.Big0) == 0 {
+		parentBlockInfo = &ParentBlockInfo{
+			Hash:    common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"),
+			Number:  big.NewInt(0),
+			GasUsed: 0,
+		}
+	} else {
+		parent, err := s.rpc.L2ParentByBlockId(ctx, lastKnownGoodBlockId)
+		if err != nil {
+			return fmt.Errorf("error getting l2 parent by block id: %w", err)
+		}
+
+		parentBlockInfo = &ParentBlockInfo{
+			Hash:    parent.Hash(),
+			Number:  parent.Number,
+			GasUsed: parent.GasUsed,
+		}
 	}
 
 	// reset l1 current to when the last known good block was inserted, and return the event.
@@ -319,7 +352,7 @@ func (s *Syncer) handleReorg(ctx context.Context, event *bindings.TaikoL1ClientB
 	payloadData, rpcError, payloadError := s.insertNewHead(
 		ctx,
 		blockProposedEvent,
-		parent,
+		parentBlockInfo,
 		s.state.GetHeadBlockID(),
 		txListBytes,
 		l1Origin,
@@ -365,15 +398,15 @@ func (s *Syncer) handleReorg(ctx context.Context, event *bindings.TaikoL1ClientB
 func (s *Syncer) insertNewHead(
 	ctx context.Context,
 	event *bindings.TaikoL1ClientBlockProposed,
-	parent *types.Header,
+	parentBlockInfo *ParentBlockInfo,
 	headBlockID *big.Int,
 	txListBytes []byte,
 	l1Origin *rawdb.L1Origin,
 ) (*engine.ExecutableData, error, error) {
 	log.Debug(
 		"Try to insert a new L2 head block",
-		"parentNumber", parent.Number,
-		"parentHash", parent.Hash(),
+		"parentNumber", parentBlockInfo.Number,
+		"parentHash", parentBlockInfo.Hash,
 		"headBlockID", headBlockID,
 		"l1Origin", l1Origin,
 	)
@@ -387,17 +420,17 @@ func (s *Syncer) insertNewHead(
 		}
 	}
 
-	parentTimestamp, err := s.rpc.TaikoL2.ParentTimestamp(&bind.CallOpts{BlockNumber: parent.Number})
+	parentTimestamp, err := s.rpc.TaikoL2.ParentTimestamp(&bind.CallOpts{BlockNumber: parentBlockInfo.Number})
 	if err != nil {
 		return nil, nil, err
 	}
 
 	// Get L2 baseFee
 	baseFee, err := s.rpc.TaikoL2.GetBasefee(
-		&bind.CallOpts{BlockNumber: parent.Number},
+		&bind.CallOpts{BlockNumber: parentBlockInfo.Number},
 		uint32(event.Meta.Timestamp-parentTimestamp),
 		uint64(event.Meta.GasLimit+uint32(s.anchorConstructor.GasLimit())),
-		parent.GasUsed,
+		parentBlockInfo.GasUsed,
 	)
 	if err != nil {
 		return nil, nil, fmt.Errorf("failed to get L2 baseFee: %w", encoding.TryParsingCustomError(err))
@@ -408,7 +441,7 @@ func (s *Syncer) insertNewHead(
 		"baseFee", baseFee,
 		"timeSinceParent", uint32(event.Meta.Timestamp-parentTimestamp),
 		"gasLimit", uint64(event.Meta.GasLimit+uint32(s.anchorConstructor.GasLimit())),
-		"parentGasUsed", parent.GasUsed,
+		"parentGasUsed", parentBlockInfo.GasUsed,
 	)
 
 	// Get withdrawals
@@ -422,9 +455,9 @@ func (s *Syncer) insertNewHead(
 		ctx,
 		new(big.Int).SetUint64(event.Meta.L1Height),
 		event.Meta.L1Hash,
-		new(big.Int).Add(parent.Number, common.Big1),
+		new(big.Int).Add(parentBlockInfo.Number, common.Big1),
 		baseFee,
-		parent.GasUsed,
+		parentBlockInfo.GasUsed,
 	)
 	if err != nil {
 		return nil, nil, fmt.Errorf("failed to create TaikoL2.anchor transaction: %w", err)
@@ -440,7 +473,7 @@ func (s *Syncer) insertNewHead(
 	payload, rpcErr, payloadErr := s.createExecutionPayloads(
 		ctx,
 		event,
-		parent.Hash(),
+		parentBlockInfo.Hash,
 		l1Origin,
 		headBlockID,
 		txListBytes,
@@ -452,7 +485,7 @@ func (s *Syncer) insertNewHead(
 		return nil, rpcErr, payloadErr
 	}
 
-	fc := &engine.ForkchoiceStateV1{HeadBlockHash: parent.Hash()}
+	fc := &engine.ForkchoiceStateV1{HeadBlockHash: parentBlockInfo.Hash}
 
 	// Update the fork choice
 	fc.HeadBlockHash = payload.BlockHash
diff --git a/driver/chain_syncer/calldata/syncer_test.go b/driver/chain_syncer/calldata/syncer_test.go
index cd5aed1ef..daf007bfd 100644
--- a/driver/chain_syncer/calldata/syncer_test.go
+++ b/driver/chain_syncer/calldata/syncer_test.go
@@ -69,7 +69,11 @@ func (s *CalldataSyncerTestSuite) TestInsertNewHead() {
 				Timestamp:   uint64(time.Now().Unix()),
 			},
 		},
-		parent,
+		&ParentBlockInfo{
+			Hash:    parent.Hash(),
+			Number:  parent.Number,
+			GasUsed: parent.GasUsed,
+		},
 		common.Big2,
 		[]byte{},
 		&rawdb.L1Origin{

From dc0ebb6842df1fe7fa44018d09cbdc015a9b5103 Mon Sep 17 00:00:00 2001
From: Jeffery Walsh <cyberhorsey@gmail.com>
Date: Mon, 15 May 2023 12:33:04 -0700
Subject: [PATCH 22/25] typo

---
 driver/chain_syncer/calldata/syncer.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/driver/chain_syncer/calldata/syncer.go b/driver/chain_syncer/calldata/syncer.go
index 7a08493b9..799a8a025 100644
--- a/driver/chain_syncer/calldata/syncer.go
+++ b/driver/chain_syncer/calldata/syncer.go
@@ -259,7 +259,7 @@ func (s *Syncer) handleReorg(ctx context.Context, event *bindings.TaikoL1ClientB
 	var block *types.Block
 	var err error
 
-	stateVars, err := s.rpc.GetProtocolStateVariables()
+	stateVars, err := s.rpc.GetProtocolStateVariables(nil)
 	if err != nil {
 		return fmt.Errorf("failed to get state variables: %w", err)
 	}

From 83fb81ab4914e0d127a41fe29bf9875de1fd6c56 Mon Sep 17 00:00:00 2001
From: David <david@taiko.xyz>
Date: Wed, 17 May 2023 01:40:38 +0800
Subject: [PATCH 23/25] feat: update some logic and add more tests based on
 #216 (#228)

---
 driver/chain_syncer/calldata/syncer.go      | 114 ++++++--------------
 driver/chain_syncer/calldata/syncer_test.go |  64 +++++++++++
 integration_test/nodes/docker-compose.yml   |   2 +-
 3 files changed, 96 insertions(+), 84 deletions(-)

diff --git a/driver/chain_syncer/calldata/syncer.go b/driver/chain_syncer/calldata/syncer.go
index 799a8a025..7b91e57ec 100644
--- a/driver/chain_syncer/calldata/syncer.go
+++ b/driver/chain_syncer/calldata/syncer.go
@@ -254,10 +254,18 @@ func (s *Syncer) handleReorg(ctx context.Context, event *bindings.TaikoL1ClientB
 	)
 
 	// rewind chain by 1 until we find a block that is still in the chain
-	var lastKnownGoodBlockId *big.Int
-	var blockId *big.Int = s.lastInsertedBlockID
-	var block *types.Block
-	var err error
+	var (
+		lastKnownGoodBlockId *big.Int
+		blockId              *big.Int
+		block                *types.Block
+		err                  error
+	)
+
+	l2Head, err := s.rpc.L2.BlockByNumber(ctx, nil)
+	if err != nil {
+		return err
+	}
+	blockId = l2Head.Number()
 
 	stateVars, err := s.rpc.GetProtocolStateVariables(nil)
 	if err != nil {
@@ -265,13 +273,15 @@ func (s *Syncer) handleReorg(ctx context.Context, event *bindings.TaikoL1ClientB
 	}
 
 	for {
-		if blockId.Cmp(big.NewInt(0)) == 0 {
-			lastKnownGoodBlockId = new(big.Int).SetUint64(0)
+		if blockId.Cmp(common.Big0) == 0 {
+			if block, err = s.rpc.L2.BlockByNumber(ctx, common.Big0); err != nil {
+				return err
+			}
+			lastKnownGoodBlockId = common.Big0
 			break
 		}
 
-		block, err = s.rpc.L2.BlockByNumber(ctx, blockId)
-		if err != nil && !errors.Is(err, ethereum.NotFound) {
+		if block, err = s.rpc.L2.BlockByNumber(ctx, blockId); err != nil && !errors.Is(err, ethereum.NotFound) {
 			return err
 		}
 
@@ -281,7 +291,7 @@ func (s *Syncer) handleReorg(ctx context.Context, event *bindings.TaikoL1ClientB
 			break
 		} else {
 			// otherwise, sub 1 from blockId and try again
-			blockId = new(big.Int).Sub(s.lastInsertedBlockID, big.NewInt(1))
+			blockId = new(big.Int).Sub(blockId, common.Big1)
 		}
 	}
 
@@ -296,91 +306,29 @@ func (s *Syncer) handleReorg(ctx context.Context, event *bindings.TaikoL1ClientB
 		"blockID", lastKnownGoodBlockId,
 	)
 
-	var parentBlockInfo *ParentBlockInfo
-
-	if lastKnownGoodBlockId.Cmp(common.Big0) == 0 {
-		parentBlockInfo = &ParentBlockInfo{
-			Hash:    common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"),
-			Number:  big.NewInt(0),
-			GasUsed: 0,
-		}
-	} else {
-		parent, err := s.rpc.L2ParentByBlockId(ctx, lastKnownGoodBlockId)
-		if err != nil {
-			return fmt.Errorf("error getting l2 parent by block id: %w", err)
-		}
-
-		parentBlockInfo = &ParentBlockInfo{
-			Hash:    parent.Hash(),
-			Number:  parent.Number,
-			GasUsed: parent.GasUsed,
-		}
-	}
-
-	// reset l1 current to when the last known good block was inserted, and return the event.
-	blockProposedEvent, _, err := s.state.ResetL1Current(ctx, &state.HeightOrID{Height: block.Number()})
-	if err != nil {
-		return fmt.Errorf("failed to reset l1 current: %w", err)
-	}
-
-	tx, err := s.rpc.L1.TransactionInBlock(
-		ctx,
-		block.Hash(),
-		blockProposedEvent.Raw.TxIndex,
-	)
+	fcRes, err := s.rpc.L2Engine.ForkchoiceUpdate(ctx, &engine.ForkchoiceStateV1{HeadBlockHash: block.Hash()}, nil)
 	if err != nil {
-		return fmt.Errorf("failed to fetch original TaikoL1.proposeBlock transaction: %w", err)
-	}
-
-	txListBytes, hint, _, err := s.txListValidator.ValidateTxList(block.Number(), tx.Data())
-	if err != nil {
-		return fmt.Errorf("failed to validate transactions list: %w", err)
-	}
-
-	if hint != txListValidator.HintOK {
-		log.Info("Invalid transactions list, insert an empty L2 block instead", "blockID", block.NumberU64())
-		txListBytes = []byte{}
-	}
-
-	l1Origin := &rawdb.L1Origin{
-		BlockID:       block.Number(),
-		L2BlockHash:   common.Hash{}, // Will be set by taiko-geth.
-		L1BlockHeight: new(big.Int).SetUint64(blockProposedEvent.Raw.BlockNumber),
-		L1BlockHash:   blockProposedEvent.Raw.BlockHash,
+		return err
 	}
-
-	payloadData, rpcError, payloadError := s.insertNewHead(
-		ctx,
-		blockProposedEvent,
-		parentBlockInfo,
-		s.state.GetHeadBlockID(),
-		txListBytes,
-		l1Origin,
-	)
-
-	if rpcError != nil {
-		return fmt.Errorf("failed to insert new head to L2 execution engine: %w", rpcError)
+	if fcRes.PayloadStatus.Status != engine.VALID {
+		return fmt.Errorf("unexpected ForkchoiceUpdate response status: %s", fcRes.PayloadStatus.Status)
 	}
 
-	if payloadError != nil {
-		log.Warn(
-			"Ignore invalid block context", "blockID", event.Id, "payloadError", payloadError, "payloadData", payloadData,
-		)
-		return nil
+	// reset l1 current to when the last known good block was inserted, and return the event.
+	if _, _, err := s.state.ResetL1Current(ctx, &state.HeightOrID{ID: lastKnownGoodBlockId}); err != nil {
+		return fmt.Errorf("failed to reset L1 current: %w", err)
 	}
 
-	log.Debug("Payload data", "hash", payloadData.BlockHash, "txs", len(payloadData.Transactions))
-
 	log.Info(
 		"🔗 Rewound chain and inserted last known good block as new head",
 		"blockID", event.Id,
-		"height", payloadData.Number,
-		"hash", payloadData.BlockHash,
+		"height", block.Number(),
+		"hash", block.Hash(),
 		"latestVerifiedBlockHeight", s.state.GetLatestVerifiedBlock().Height,
 		"latestVerifiedBlockHash", s.state.GetLatestVerifiedBlock().Hash,
-		"transactions", len(payloadData.Transactions),
-		"baseFee", payloadData.BaseFeePerGas,
-		"withdrawals", len(payloadData.Withdrawals),
+		"transactions", len(block.Transactions()),
+		"baseFee", block.BaseFee(),
+		"withdrawals", len(block.Withdrawals()),
 	)
 
 	metrics.DriverL1CurrentHeightGauge.Update(int64(event.Raw.BlockNumber))
diff --git a/driver/chain_syncer/calldata/syncer_test.go b/driver/chain_syncer/calldata/syncer_test.go
index daf007bfd..530889f78 100644
--- a/driver/chain_syncer/calldata/syncer_test.go
+++ b/driver/chain_syncer/calldata/syncer_test.go
@@ -9,16 +9,20 @@ import (
 
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/core/rawdb"
+	"github.com/ethereum/go-ethereum/core/types"
+	"github.com/ethereum/go-ethereum/crypto"
 	"github.com/stretchr/testify/suite"
 	"github.com/taikoxyz/taiko-client/bindings"
 	"github.com/taikoxyz/taiko-client/driver/chain_syncer/beaconsync"
 	"github.com/taikoxyz/taiko-client/driver/state"
+	"github.com/taikoxyz/taiko-client/proposer"
 	"github.com/taikoxyz/taiko-client/testutils"
 )
 
 type CalldataSyncerTestSuite struct {
 	testutils.ClientTestSuite
 	s *Syncer
+	p testutils.Proposer
 }
 
 func (s *CalldataSyncerTestSuite) SetupTest() {
@@ -36,6 +40,22 @@ func (s *CalldataSyncerTestSuite) SetupTest() {
 	)
 	s.Nil(err)
 	s.s = syncer
+
+	prop := new(proposer.Proposer)
+	l1ProposerPrivKey, err := crypto.ToECDSA(common.Hex2Bytes(os.Getenv("L1_PROPOSER_PRIVATE_KEY")))
+	s.Nil(err)
+	proposeInterval := 1024 * time.Hour // No need to periodically propose transactions list in unit tests
+	s.Nil(proposer.InitFromConfig(context.Background(), prop, (&proposer.Config{
+		L1Endpoint:              os.Getenv("L1_NODE_WS_ENDPOINT"),
+		L2Endpoint:              os.Getenv("L2_EXECUTION_ENGINE_WS_ENDPOINT"),
+		TaikoL1Address:          common.HexToAddress(os.Getenv("TAIKO_L1_ADDRESS")),
+		TaikoL2Address:          common.HexToAddress(os.Getenv("TAIKO_L2_ADDRESS")),
+		L1ProposerPrivKey:       l1ProposerPrivKey,
+		L2SuggestedFeeRecipient: common.HexToAddress(os.Getenv("L2_SUGGESTED_FEE_RECIPIENT")),
+		ProposeInterval:         &proposeInterval,
+	})))
+
+	s.p = prop
 }
 
 func (s *CalldataSyncerTestSuite) TestProcessL1Blocks() {
@@ -86,6 +106,50 @@ func (s *CalldataSyncerTestSuite) TestInsertNewHead() {
 	s.Nil(payloadErr)
 }
 
+func (s *CalldataSyncerTestSuite) TestHandleReorgToGenesis() {
+	testutils.ProposeAndInsertEmptyBlocks(&s.ClientTestSuite, s.p, s.s)
+
+	l2Head1, err := s.s.rpc.L2.BlockByNumber(context.Background(), nil)
+	s.Nil(err)
+	s.Greater(l2Head1.NumberU64(), uint64(0))
+	s.NotZero(s.s.lastInsertedBlockID.Uint64())
+	s.s.lastInsertedBlockID = common.Big0 // let the chain reorg to genesis
+
+	s.Nil(s.s.handleReorg(context.Background(), &bindings.TaikoL1ClientBlockProposed{
+		Id:  l2Head1.Number(),
+		Raw: types.Log{Removed: true},
+	}))
+
+	l2Head2, err := s.s.rpc.L2.BlockByNumber(context.Background(), nil)
+	s.Nil(err)
+	s.Equal(uint64(0), l2Head2.NumberU64())
+}
+
+func (s *CalldataSyncerTestSuite) TestHandleReorgToNoneGenesis() {
+	testutils.ProposeAndInsertEmptyBlocks(&s.ClientTestSuite, s.p, s.s)
+
+	l2Head1, err := s.s.rpc.L2.BlockByNumber(context.Background(), nil)
+	s.Nil(err)
+	s.Greater(l2Head1.NumberU64(), uint64(0))
+	s.NotZero(s.s.lastInsertedBlockID.Uint64())
+	s.s.lastInsertedBlockID = common.Big1 // let the chain reorg to height 1
+
+	s.Nil(s.s.handleReorg(context.Background(), &bindings.TaikoL1ClientBlockProposed{
+		Id:  l2Head1.Number(),
+		Raw: types.Log{Removed: true},
+	}))
+
+	l2Head2, err := s.s.rpc.L2.BlockByNumber(context.Background(), nil)
+	s.Nil(err)
+	s.Equal(uint64(1), l2Head2.NumberU64())
+
+	testutils.ProposeAndInsertEmptyBlocks(&s.ClientTestSuite, s.p, s.s)
+	l2Head3, err := s.s.rpc.L2.BlockByNumber(context.Background(), nil)
+	s.Nil(err)
+	s.Greater(l2Head3.NumberU64(), l2Head2.NumberU64())
+	s.Greater(s.s.lastInsertedBlockID.Uint64(), uint64(1))
+}
+
 func TestCalldataSyncerTestSuite(t *testing.T) {
 	suite.Run(t, new(CalldataSyncerTestSuite))
 }
diff --git a/integration_test/nodes/docker-compose.yml b/integration_test/nodes/docker-compose.yml
index 64a816b99..04f852f4b 100644
--- a/integration_test/nodes/docker-compose.yml
+++ b/integration_test/nodes/docker-compose.yml
@@ -14,7 +14,7 @@ services:
       - "0.0.0.0"
 
   l2_execution_engine:
-    image: gcr.io/evmchain/taiko-geth:taiko
+    image: gcr.io/evmchain/taiko-geth:sha-f8be24a # TODO: change back to taiko tag
     restart: unless-stopped
     pull_policy: always
     volumes:

From 2d3c7473a69eff14a1c888b0d252b30d8e79f7f5 Mon Sep 17 00:00:00 2001
From: Jeffery Walsh <cyberhorsey@gmail.com>
Date: Tue, 16 May 2023 10:47:19 -0700
Subject: [PATCH 24/25] remove parentblockinfo

---
 driver/chain_syncer/calldata/syncer.go      | 36 +++++++--------------
 driver/chain_syncer/calldata/syncer_test.go |  6 +---
 2 files changed, 13 insertions(+), 29 deletions(-)

diff --git a/driver/chain_syncer/calldata/syncer.go b/driver/chain_syncer/calldata/syncer.go
index 7b91e57ec..7e11d785d 100644
--- a/driver/chain_syncer/calldata/syncer.go
+++ b/driver/chain_syncer/calldata/syncer.go
@@ -26,14 +26,6 @@ import (
 	txListValidator "github.com/taikoxyz/taiko-client/pkg/tx_list_validator"
 )
 
-// ParentBlockInfo is an abstraction between *types.Header and our code, to allow passing in
-// a zero hash and other zero-value fields.
-type ParentBlockInfo struct {
-	Hash    common.Hash
-	Number  *big.Int
-	GasUsed uint64
-}
-
 // Syncer responsible for letting the L2 execution engine catching up with protocol's latest
 // pending block through deriving L1 calldata.
 type Syncer struct {
@@ -196,11 +188,7 @@ func (s *Syncer) onBlockProposed(
 	payloadData, rpcError, payloadError := s.insertNewHead(
 		ctx,
 		event,
-		&ParentBlockInfo{
-			Hash:    parent.Hash(),
-			Number:  parent.Number,
-			GasUsed: parent.GasUsed,
-		},
+		parent,
 		s.state.GetHeadBlockID(),
 		txListBytes,
 		l1Origin,
@@ -346,15 +334,15 @@ func (s *Syncer) handleReorg(ctx context.Context, event *bindings.TaikoL1ClientB
 func (s *Syncer) insertNewHead(
 	ctx context.Context,
 	event *bindings.TaikoL1ClientBlockProposed,
-	parentBlockInfo *ParentBlockInfo,
+	parent *types.Header,
 	headBlockID *big.Int,
 	txListBytes []byte,
 	l1Origin *rawdb.L1Origin,
 ) (*engine.ExecutableData, error, error) {
 	log.Debug(
 		"Try to insert a new L2 head block",
-		"parentNumber", parentBlockInfo.Number,
-		"parentHash", parentBlockInfo.Hash,
+		"parentNumber", parent.Number,
+		"parentHash", parent.Hash(),
 		"headBlockID", headBlockID,
 		"l1Origin", l1Origin,
 	)
@@ -368,17 +356,17 @@ func (s *Syncer) insertNewHead(
 		}
 	}
 
-	parentTimestamp, err := s.rpc.TaikoL2.ParentTimestamp(&bind.CallOpts{BlockNumber: parentBlockInfo.Number})
+	parentTimestamp, err := s.rpc.TaikoL2.ParentTimestamp(&bind.CallOpts{BlockNumber: parent.Number})
 	if err != nil {
 		return nil, nil, err
 	}
 
 	// Get L2 baseFee
 	baseFee, err := s.rpc.TaikoL2.GetBasefee(
-		&bind.CallOpts{BlockNumber: parentBlockInfo.Number},
+		&bind.CallOpts{BlockNumber: parent.Number},
 		uint32(event.Meta.Timestamp-parentTimestamp),
 		uint64(event.Meta.GasLimit+uint32(s.anchorConstructor.GasLimit())),
-		parentBlockInfo.GasUsed,
+		parent.GasUsed,
 	)
 	if err != nil {
 		return nil, nil, fmt.Errorf("failed to get L2 baseFee: %w", encoding.TryParsingCustomError(err))
@@ -389,7 +377,7 @@ func (s *Syncer) insertNewHead(
 		"baseFee", baseFee,
 		"timeSinceParent", uint32(event.Meta.Timestamp-parentTimestamp),
 		"gasLimit", uint64(event.Meta.GasLimit+uint32(s.anchorConstructor.GasLimit())),
-		"parentGasUsed", parentBlockInfo.GasUsed,
+		"parentGasUsed", parent.GasUsed,
 	)
 
 	// Get withdrawals
@@ -403,9 +391,9 @@ func (s *Syncer) insertNewHead(
 		ctx,
 		new(big.Int).SetUint64(event.Meta.L1Height),
 		event.Meta.L1Hash,
-		new(big.Int).Add(parentBlockInfo.Number, common.Big1),
+		new(big.Int).Add(parent.Number, common.Big1),
 		baseFee,
-		parentBlockInfo.GasUsed,
+		parent.GasUsed,
 	)
 	if err != nil {
 		return nil, nil, fmt.Errorf("failed to create TaikoL2.anchor transaction: %w", err)
@@ -421,7 +409,7 @@ func (s *Syncer) insertNewHead(
 	payload, rpcErr, payloadErr := s.createExecutionPayloads(
 		ctx,
 		event,
-		parentBlockInfo.Hash,
+		parent.Hash(),
 		l1Origin,
 		headBlockID,
 		txListBytes,
@@ -433,7 +421,7 @@ func (s *Syncer) insertNewHead(
 		return nil, rpcErr, payloadErr
 	}
 
-	fc := &engine.ForkchoiceStateV1{HeadBlockHash: parentBlockInfo.Hash}
+	fc := &engine.ForkchoiceStateV1{HeadBlockHash: parent.Hash()}
 
 	// Update the fork choice
 	fc.HeadBlockHash = payload.BlockHash
diff --git a/driver/chain_syncer/calldata/syncer_test.go b/driver/chain_syncer/calldata/syncer_test.go
index 530889f78..920c62ea7 100644
--- a/driver/chain_syncer/calldata/syncer_test.go
+++ b/driver/chain_syncer/calldata/syncer_test.go
@@ -89,11 +89,7 @@ func (s *CalldataSyncerTestSuite) TestInsertNewHead() {
 				Timestamp:   uint64(time.Now().Unix()),
 			},
 		},
-		&ParentBlockInfo{
-			Hash:    parent.Hash(),
-			Number:  parent.Number,
-			GasUsed: parent.GasUsed,
-		},
+		parent,
 		common.Big2,
 		[]byte{},
 		&rawdb.L1Origin{

From 77baff877ab19b8eda7211e7381e899a48df9d8a Mon Sep 17 00:00:00 2001
From: David <david@taiko.xyz>
Date: Wed, 17 May 2023 01:54:55 +0800
Subject: [PATCH 25/25] feat: fix tests and rename Id to ID

---
 driver/chain_syncer/calldata/syncer.go | 33 ++++++++++++++------------
 1 file changed, 18 insertions(+), 15 deletions(-)

diff --git a/driver/chain_syncer/calldata/syncer.go b/driver/chain_syncer/calldata/syncer.go
index 7e11d785d..950845f1e 100644
--- a/driver/chain_syncer/calldata/syncer.go
+++ b/driver/chain_syncer/calldata/syncer.go
@@ -243,17 +243,20 @@ func (s *Syncer) handleReorg(ctx context.Context, event *bindings.TaikoL1ClientB
 
 	// rewind chain by 1 until we find a block that is still in the chain
 	var (
-		lastKnownGoodBlockId *big.Int
-		blockId              *big.Int
+		lastKnownGoodBlockID *big.Int
+		blockID              *big.Int = s.lastInsertedBlockID
 		block                *types.Block
 		err                  error
 	)
 
-	l2Head, err := s.rpc.L2.BlockByNumber(ctx, nil)
-	if err != nil {
-		return err
+	// if `lastInsertedBlockID` has not been set, we use current L2 chain head as blockID instead
+	if blockID == nil {
+		l2Head, err := s.rpc.L2.BlockByNumber(ctx, nil)
+		if err != nil {
+			return err
+		}
+		blockID = l2Head.Number()
 	}
-	blockId = l2Head.Number()
 
 	stateVars, err := s.rpc.GetProtocolStateVariables(nil)
 	if err != nil {
@@ -261,37 +264,37 @@ func (s *Syncer) handleReorg(ctx context.Context, event *bindings.TaikoL1ClientB
 	}
 
 	for {
-		if blockId.Cmp(common.Big0) == 0 {
+		if blockID.Cmp(common.Big0) == 0 {
 			if block, err = s.rpc.L2.BlockByNumber(ctx, common.Big0); err != nil {
 				return err
 			}
-			lastKnownGoodBlockId = common.Big0
+			lastKnownGoodBlockID = common.Big0
 			break
 		}
 
-		if block, err = s.rpc.L2.BlockByNumber(ctx, blockId); err != nil && !errors.Is(err, ethereum.NotFound) {
+		if block, err = s.rpc.L2.BlockByNumber(ctx, blockID); err != nil && !errors.Is(err, ethereum.NotFound) {
 			return err
 		}
 
-		if block != nil && blockId.Uint64() < stateVars.NumBlocks {
+		if block != nil && blockID.Uint64() < stateVars.NumBlocks {
 			// block exists, we can rewind to this block
-			lastKnownGoodBlockId = blockId
+			lastKnownGoodBlockID = blockID
 			break
 		} else {
 			// otherwise, sub 1 from blockId and try again
-			blockId = new(big.Int).Sub(blockId, common.Big1)
+			blockID = new(big.Int).Sub(blockID, common.Big1)
 		}
 	}
 
 	// shouldn't be able to reach this error because of the 0 check above
 	// but just in case
-	if lastKnownGoodBlockId == nil {
+	if lastKnownGoodBlockID == nil {
 		return fmt.Errorf("failed to find last known good block ID after reorg")
 	}
 
 	log.Info(
 		"🔗 Last known good block ID before reorg found",
-		"blockID", lastKnownGoodBlockId,
+		"blockID", lastKnownGoodBlockID,
 	)
 
 	fcRes, err := s.rpc.L2Engine.ForkchoiceUpdate(ctx, &engine.ForkchoiceStateV1{HeadBlockHash: block.Hash()}, nil)
@@ -303,7 +306,7 @@ func (s *Syncer) handleReorg(ctx context.Context, event *bindings.TaikoL1ClientB
 	}
 
 	// reset l1 current to when the last known good block was inserted, and return the event.
-	if _, _, err := s.state.ResetL1Current(ctx, &state.HeightOrID{ID: lastKnownGoodBlockId}); err != nil {
+	if _, _, err := s.state.ResetL1Current(ctx, &state.HeightOrID{ID: lastKnownGoodBlockID}); err != nil {
 		return fmt.Errorf("failed to reset L1 current: %w", err)
 	}