Skip to content
This repository has been archived by the owner on May 11, 2024. It is now read-only.

Commit

Permalink
feat(rpc): improve reorg checks
Browse files Browse the repository at this point in the history
  • Loading branch information
davidtaikocha committed Jan 17, 2024
1 parent fdcb4bc commit 9816c64
Show file tree
Hide file tree
Showing 5 changed files with 166 additions and 5 deletions.
5 changes: 5 additions & 0 deletions driver/anchor_tx_constructor/anchor_tx_constructor.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,3 +153,8 @@ func (c *AnchorTxConstructor) signTxPayload(hash []byte) ([]byte, error) {
func (c *AnchorTxConstructor) GasLimit() uint64 {
return anchorGasLimit
}

// SignalServiceAddress returns protocol's L1 singalService constant address.
func (c *AnchorTxConstructor) SignalServiceAddress() common.Address {
return c.signalServiceAddress
}
1 change: 1 addition & 0 deletions driver/chain_syncer/calldata/syncer.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ func (s *Syncer) onBlockProposed(
reorged, l1CurrentToReset, lastInsertedBlockIDToReset, err = s.rpc.CheckL1ReorgFromL2EE(
ctx,
new(big.Int).Sub(event.BlockId, common.Big1),
s.anchorConstructor.SignalServiceAddress(),
)
if err != nil {
return fmt.Errorf("failed to check whether L1 chain has been reorged: %w", err)
Expand Down
18 changes: 15 additions & 3 deletions driver/driver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,11 @@ func (s *DriverTestSuite) TestCheckL1ReorgToHigherFork() {
s.Greater(l2Head2.Number.Uint64(), l2Head1.Number.Uint64())
s.Greater(l1Head2.Number.Uint64(), l1Head1.Number.Uint64())

reorged, _, _, err := s.RPCClient.CheckL1ReorgFromL2EE(context.Background(), l2Head2.Number)
reorged, _, _, err := s.RPCClient.CheckL1ReorgFromL2EE(
context.Background(),
l2Head2.Number,
common.HexToAddress(os.Getenv("L1_SIGNAL_SERVICE_CONTRACT_ADDRESS")),
)
s.Nil(err)
s.False(reorged)

Expand Down Expand Up @@ -202,7 +206,11 @@ func (s *DriverTestSuite) TestCheckL1ReorgToLowerFork() {
s.Greater(l2Head2.Number.Uint64(), l2Head1.Number.Uint64())
s.Greater(l1Head2.Number.Uint64(), l1Head1.Number.Uint64())

reorged, _, _, err := s.RPCClient.CheckL1ReorgFromL2EE(context.Background(), l2Head2.Number)
reorged, _, _, err := s.RPCClient.CheckL1ReorgFromL2EE(
context.Background(),
l2Head2.Number,
common.HexToAddress(os.Getenv("L1_SIGNAL_SERVICE_CONTRACT_ADDRESS")),
)
s.Nil(err)
s.False(reorged)

Expand Down Expand Up @@ -258,7 +266,11 @@ func (s *DriverTestSuite) TestCheckL1ReorgToSameHeightFork() {
s.Greater(l2Head2.Number.Uint64(), l2Head1.Number.Uint64())
s.Greater(l1Head2.Number.Uint64(), l1Head1.Number.Uint64())

reorged, _, _, err := s.RPCClient.CheckL1ReorgFromL2EE(context.Background(), l2Head2.Number)
reorged, _, _, err := s.RPCClient.CheckL1ReorgFromL2EE(
context.Background(),
l2Head2.Number,
common.HexToAddress(os.Getenv("L1_SIGNAL_SERVICE_CONTRACT_ADDRESS")),
)
s.Nil(err)
s.False(reorged)

Expand Down
136 changes: 134 additions & 2 deletions pkg/rpc/methods.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import (
"golang.org/x/sync/errgroup"

"github.com/taikoxyz/taiko-client/bindings"
"github.com/taikoxyz/taiko-client/bindings"
"github.com/taikoxyz/taiko-client/bindings/encoding"
)

var (
Expand Down Expand Up @@ -386,7 +388,11 @@ func (c *Client) GetStorageRoot(

// CheckL1ReorgFromL2EE checks whether the L1 chain has been reorged from the L1Origin records in L2 EE,
// if so, returns the l1Current cursor and L2 blockID that need to reset to.
func (c *Client) CheckL1ReorgFromL2EE(ctx context.Context, blockID *big.Int) (bool, *types.Header, *big.Int, error) {
func (c *Client) CheckL1ReorgFromL2EE(
ctx context.Context,
blockID *big.Int,
l1SignalService common.Address,
) (bool, *types.Header, *big.Int, error) {
var (
reorged bool
l1CurrentToReset *types.Header
Expand Down Expand Up @@ -467,6 +473,20 @@ func (c *Client) CheckL1ReorgFromL2EE(ctx context.Context, blockID *big.Int) (bo
continue
}

isSyncedL1SnippetValid, err := c.CheckL1ReorgFromAnchor(
ctx, blockID, l1Origin.L1BlockHeight.Uint64(), l1SignalService,
)
if err != nil {
return false, nil, nil, fmt.Errorf("failed to check L1 reorg from anchor transaction: %w", err)
}

if !isSyncedL1SnippetValid {
log.Info("Reorg detected due to invalid L1 snippet", "blockID", blockID)
reorged = true
blockID = new(big.Int).Sub(blockID, common.Big1)
continue
}

l1CurrentToReset = l1Header
blockIDToReset = l1Origin.BlockID
break
Expand All @@ -478,11 +498,123 @@ func (c *Client) CheckL1ReorgFromL2EE(ctx context.Context, blockID *big.Int) (bo
"l1CurrentToResetNumber", l1CurrentToReset.Number,
"l1CurrentToResetHash", l1CurrentToReset.Hash(),
"blockIDToReset", blockIDToReset,
)

return reorged, l1CurrentToReset, blockIDToReset, nil

Check failure on line 502 in pkg/rpc/methods.go

View workflow job for this annotation

GitHub Actions / Lint

syntax error: unexpected return, expected expression) (typecheck)

Check failure on line 502 in pkg/rpc/methods.go

View workflow job for this annotation

GitHub Actions / Lint

syntax error: unexpected return, expected expression) (typecheck)

Check failure on line 502 in pkg/rpc/methods.go

View workflow job for this annotation

GitHub Actions / Lint

syntax error: unexpected return, expected expression) (typecheck)
}

func (c *Client) CheckL1ReorgFromAnchor(
ctx context.Context,
blockID *big.Int,
l1Height uint64,
l1SignalService common.Address,
) (bool, error) {
log.Info("Check L1 reorg from anchor", "blockID", blockID)
block, err := c.L2.BlockByNumber(ctx, blockID)
if err != nil {
return false, err
}
parent, err := c.L2.BlockByHash(ctx, block.ParentHash())
if err != nil {
return false, err
}

l1BlockHash, l1SignalRoot, l1HeightInAnchor, parentGasUsed, err := c.getSyncedL1SnippetFromAnchcor(
ctx,
block.Transactions()[0],
)
if err != nil {
return false, err
}

if l1HeightInAnchor != l1Height {
log.Info("Reorg detected due to L1 height mismatch", "blockID", blockID)
return true, nil
}

if parentGasUsed != uint32(parent.GasUsed()) {
log.Info("Reorg detected due to parent gas used mismatch", "blockID", blockID)
return true, nil
}

l1Header, err := c.L1.HeaderByHash(ctx, l1BlockHash)
if err != nil {
return false, err
}

currentRoot, err := c.GetStorageRoot(ctx, c.L1GethClient, l1SignalService, l1Header.Number)
if err != nil {
return false, err
}

if currentRoot != l1SignalRoot {
log.Info("Reorg detected due to L1 signal root mismatch", "blockID", blockID)
return true, nil
}

return false, nil
}

func (c *Client) getSyncedL1SnippetFromAnchcor(
ctx context.Context,
tx *types.Transaction,
) (
l1BlockHash common.Hash,
l1SignalRoot common.Hash,
l1Height uint64,
parentGasUsed uint32,
err error,
) {
method, err := encoding.TaikoL2ABI.MethodById(tx.Data())
if err != nil {
return common.Hash{}, common.Hash{}, 0, 0, err
}

if method.Name != "anchor" {
return common.Hash{}, common.Hash{}, 0, 0, fmt.Errorf("invalid method name for anchor transaction: %s", method.Name)
}

args := map[string]interface{}{}

if err := method.Inputs.UnpackIntoMap(args, tx.Data()[4:]); err != nil {
return common.Hash{}, common.Hash{}, 0, 0, err
}

l1BlockHash, ok := args["l1BlockHash"].([32]byte)
if !ok {
return common.Hash{},
common.Hash{},
0,
0,
fmt.Errorf("failed to parse l1BlockHash from anchor transaction calldata")
}
l1SignalRoot, ok = args["l1SignalRoot"].([32]byte)
if !ok {
return common.Hash{},
common.Hash{},
0,
0,
fmt.Errorf("failed to parse l1SignalRoot from anchor transaction calldata")
}
l1Height, ok = args["l1Height"].(uint64)
if !ok {
return common.Hash{},
common.Hash{},
0,
0,
fmt.Errorf("failed to parse l1Height from anchor transaction calldata")
}
parentGasUsed, ok = args["parentGasUsed"].(uint32)
if !ok {
return common.Hash{},
common.Hash{},
0,
0,
fmt.Errorf("failed to parse parentGasUsed from anchor transaction calldata")
}

return l1BlockHash, l1SignalRoot, l1Height, parentGasUsed, nil
}

// CheckL1ReorgFromL1Cursor checks whether the L1 chain has been reorged from the given l1Current cursor,
// if so, returns the l1Current cursor that need to reset to.
func (c *Client) CheckL1ReorgFromL1Cursor(
Expand Down
11 changes: 11 additions & 0 deletions prover/prover.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ type Prover struct {
l1Current *types.Header
reorgDetectedFlag bool
tiers []*rpc.TierProviderTierWithID
l1SingalService common.Address

// Proof submitters
proofSubmitters []proofSubmitter.Submitter
Expand Down Expand Up @@ -132,6 +133,15 @@ func InitFromConfig(ctx context.Context, p *Prover, cfg *Config) (err error) {

log.Info("Protocol configs", "configs", p.protocolConfigs)

p.l1SingalService, err = p.rpc.TaikoL1.Resolve0(
&bind.CallOpts{Context: ctx},
rpc.StringToBytes32("signal_service"),
false,
)
if err != nil {
return fmt.Errorf("failed to resolve L1 signal service address: %w", err)
}

p.proverAddress = crypto.PubkeyToAddress(p.cfg.L1ProverPrivKey.PublicKey)

chBufferSize := p.protocolConfigs.BlockMaxProposals
Expand Down Expand Up @@ -551,6 +561,7 @@ func (p *Prover) onBlockProposed(
reorged, l1CurrentToReset, lastHandledBlockIDToReset, err := p.rpc.CheckL1ReorgFromL2EE(
ctx,
new(big.Int).Sub(event.BlockId, common.Big1),
p.l1SingalService,
)
if err != nil {
return fmt.Errorf("failed to check whether L1 chain was reorged from L2EE (eventID %d): %w", event.BlockId, err)
Expand Down

0 comments on commit 9816c64

Please sign in to comment.