Skip to content
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

fix(taiko-client): valid status check in BatchGetBlocksProofStatus #18595

Merged
merged 8 commits into from
Dec 16, 2024
18 changes: 17 additions & 1 deletion packages/taiko-client/pkg/rpc/ethclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package rpc
import (
"context"
"errors"
"fmt"
"math/big"
"time"

Expand Down Expand Up @@ -164,7 +165,7 @@ func (c *EthClient) BatchHeadersByNumbers(ctx context.Context, numbers []*big.In
for i, blockNum := range numbers {
reqs[i] = rpc.BatchElem{
Method: "eth_getBlockByNumber",
Args: []interface{}{blockNum, false},
Args: []interface{}{toBlockNumArg(blockNum), false},
Result: &results[i],
}
}
Expand All @@ -180,6 +181,21 @@ func (c *EthClient) BatchHeadersByNumbers(ctx context.Context, numbers []*big.In
return results, nil
}

func toBlockNumArg(number *big.Int) string {
if number == nil {
return "latest"
}
if number.Sign() >= 0 {
return hexutil.EncodeBig(number)
}
// It's negative.
if number.IsInt64() {
return rpc.BlockNumber(number.Int64()).String()
}
// It's negative and large, which is invalid.
return fmt.Sprintf("<invalid %d>", number)
}

// TransactionByHash returns the transaction with the given hash.
func (c *EthClient) TransactionByHash(
ctx context.Context,
Expand Down
58 changes: 25 additions & 33 deletions packages/taiko-client/pkg/rpc/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -265,22 +265,19 @@ func BatchGetBlocksProofStatus(
defer cancel()
var (
parentHashes = make([][32]byte, len(ids))
parents = make([]*types.Header, len(ids))
blockIDs = make([]uint64, len(ids))
parentIDs = make([]*big.Int, len(ids))
blockIDs = make([]*big.Int, len(ids))
blocks = make([]uint64, len(ids))
result = make([]*BlockProofStatus, len(ids))
highestBlockID = big.NewInt(0)
mask-pp marked this conversation as resolved.
Show resolved Hide resolved
)
// Get the local L2 parent header.
g, gCtx := errgroup.WithContext(ctxWithTimeout)
g, _ := errgroup.WithContext(ctxWithTimeout)
for i, id := range ids {
g.Go(func() error {
parent, err := cli.L2.HeaderByNumber(gCtx, new(big.Int).Sub(id, common.Big1))
if err != nil {
return err
}
parentHashes[i] = parent.Hash()
parents[i] = parent
blockIDs[i] = id.Uint64()
parentIDs[i] = new(big.Int).Sub(id, common.Big1)
blockIDs[i] = id
blocks[i] = id.Uint64()
YoGhurt111 marked this conversation as resolved.
Show resolved Hide resolved
if id.Cmp(highestBlockID) > 0 {
highestBlockID = id
}
Expand All @@ -290,50 +287,45 @@ func BatchGetBlocksProofStatus(
if gErr := g.Wait(); gErr != nil {
return nil, gErr
}

parents, err := cli.L2.BatchHeadersByNumbers(ctxWithTimeout, parentIDs)
if err != nil {
return nil, err
}
for i := range ids {
parentHashes[i] = parents[i].Hash()
}
// Get the transition state from TaikoL1 contract.
transitions, err := cli.TaikoL1.GetTransitions(
&bind.CallOpts{Context: ctxWithTimeout},
blockIDs,
blocks,
parentHashes,
)
if err != nil {
return nil, err
}
highestHeader, err := cli.WaitL2Header(ctxWithTimeout, highestBlockID)
_, err = cli.WaitL2Header(ctxWithTimeout, highestBlockID)
if err != nil {
return nil, err
}
g, gCtx = errgroup.WithContext(ctxWithTimeout)
blockHeaders, err := cli.L2.BatchHeadersByNumbers(ctxWithTimeout, blockIDs)
mask-pp marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return nil, err
}
g, _ = errgroup.WithContext(ctxWithTimeout)
for i, transition := range transitions {
// No proof on chain
if transition.BlockHash == (common.Hash{}) {
result[i] = &BlockProofStatus{IsSubmitted: false, ParentHeader: parents[i]}
continue
}
g.Go(func() error {
if err != nil {
return err
}
var (
localBlockHash common.Hash
localStateRoot [32]byte
)
if i+1 < len(parents) {
localBlockHash = parents[i+1].Hash()
localStateRoot = parents[i+1].Root
} else {
localBlockHash = highestHeader.Hash()
localStateRoot = highestHeader.Root
}

if localBlockHash != transition.BlockHash ||
(transition.StateRoot != (common.Hash{}) && transition.StateRoot != localStateRoot) {
if blockHeaders[i].Hash() != transition.BlockHash ||
(transition.StateRoot != (common.Hash{}) && transition.StateRoot != blockHeaders[i].Root) {
log.Info(
"Different block hash or state root detected, try submitting a contest",
"localBlockHash", localBlockHash,
"localBlockHash", blockHeaders[i].Hash(),
"protocolTransitionBlockHash", common.BytesToHash(transition.BlockHash[:]),
"localStateRoot", localStateRoot,
"localStateRoot", blockHeaders[i].Root,
"protocolTransitionStateRoot", common.BytesToHash(transition.StateRoot[:]),
)
result[i] = &BlockProofStatus{
Expand Down
Loading