From 26e486ed8b780eb2cffaa9eca72af9f4d5949e3e Mon Sep 17 00:00:00 2001 From: gavin Date: Mon, 16 Dec 2024 10:18:22 +0800 Subject: [PATCH 1/3] fix(taiko-client): valid status check in `BatchGetBlocksProofStatus` --- packages/taiko-client/pkg/rpc/ethclient.go | 18 ++++++- packages/taiko-client/pkg/rpc/utils.go | 58 ++++++++++------------ 2 files changed, 42 insertions(+), 34 deletions(-) diff --git a/packages/taiko-client/pkg/rpc/ethclient.go b/packages/taiko-client/pkg/rpc/ethclient.go index f16e43d57b2..23254d1b666 100644 --- a/packages/taiko-client/pkg/rpc/ethclient.go +++ b/packages/taiko-client/pkg/rpc/ethclient.go @@ -3,6 +3,7 @@ package rpc import ( "context" "errors" + "fmt" "math/big" "time" @@ -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], } } @@ -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("", number) +} + // TransactionByHash returns the transaction with the given hash. func (c *EthClient) TransactionByHash( ctx context.Context, diff --git a/packages/taiko-client/pkg/rpc/utils.go b/packages/taiko-client/pkg/rpc/utils.go index 570d72da166..30a222c04c1 100644 --- a/packages/taiko-client/pkg/rpc/utils.go +++ b/packages/taiko-client/pkg/rpc/utils.go @@ -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) ) // 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() if id.Cmp(highestBlockID) > 0 { highestBlockID = id } @@ -290,21 +287,31 @@ 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) + if err != nil { + return nil, err + } + g, _ = errgroup.WithContext(ctxWithTimeout) for i, transition := range transitions { // No proof on chain if transition.BlockHash == (common.Hash{}) { @@ -312,28 +319,13 @@ func BatchGetBlocksProofStatus( 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{ From 0488bf5b79771206570bb65b89cfa5282c9cc1da Mon Sep 17 00:00:00 2001 From: gavin Date: Mon, 16 Dec 2024 14:48:55 +0800 Subject: [PATCH 2/3] rename --- packages/taiko-client/pkg/rpc/utils.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/taiko-client/pkg/rpc/utils.go b/packages/taiko-client/pkg/rpc/utils.go index 30a222c04c1..9e21b964bba 100644 --- a/packages/taiko-client/pkg/rpc/utils.go +++ b/packages/taiko-client/pkg/rpc/utils.go @@ -267,7 +267,7 @@ func BatchGetBlocksProofStatus( parentHashes = make([][32]byte, len(ids)) parentIDs = make([]*big.Int, len(ids)) blockIDs = make([]*big.Int, len(ids)) - blocks = make([]uint64, len(ids)) + uint64BlockIDs = make([]uint64, len(ids)) result = make([]*BlockProofStatus, len(ids)) highestBlockID = big.NewInt(0) ) @@ -277,7 +277,7 @@ func BatchGetBlocksProofStatus( g.Go(func() error { parentIDs[i] = new(big.Int).Sub(id, common.Big1) blockIDs[i] = id - blocks[i] = id.Uint64() + uint64BlockIDs[i] = id.Uint64() if id.Cmp(highestBlockID) > 0 { highestBlockID = id } @@ -297,7 +297,7 @@ func BatchGetBlocksProofStatus( // Get the transition state from TaikoL1 contract. transitions, err := cli.TaikoL1.GetTransitions( &bind.CallOpts{Context: ctxWithTimeout}, - blocks, + uint64BlockIDs, parentHashes, ) if err != nil { From 615e73bf14a79c34f4a5a05b1c6826722b043045 Mon Sep 17 00:00:00 2001 From: gavin Date: Mon, 16 Dec 2024 19:47:48 +0800 Subject: [PATCH 3/3] optimizations based on comments --- packages/taiko-client/pkg/rpc/utils.go | 31 +++++++++++++------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/packages/taiko-client/pkg/rpc/utils.go b/packages/taiko-client/pkg/rpc/utils.go index 9e21b964bba..c425b82158f 100644 --- a/packages/taiko-client/pkg/rpc/utils.go +++ b/packages/taiko-client/pkg/rpc/utils.go @@ -2,6 +2,7 @@ package rpc import ( "context" + "errors" "math/big" "os" "os/signal" @@ -32,6 +33,7 @@ var ( syscall.SIGTERM, syscall.SIGQUIT, } + ErrInvalidLength = errors.New("invalid length") ) // GetProtocolConfigs gets the protocol configs from TaikoL1 contract. @@ -271,26 +273,22 @@ func BatchGetBlocksProofStatus( result = make([]*BlockProofStatus, len(ids)) highestBlockID = big.NewInt(0) ) - // Get the local L2 parent header. - g, _ := errgroup.WithContext(ctxWithTimeout) for i, id := range ids { - g.Go(func() error { - parentIDs[i] = new(big.Int).Sub(id, common.Big1) - blockIDs[i] = id - uint64BlockIDs[i] = id.Uint64() - if id.Cmp(highestBlockID) > 0 { - highestBlockID = id - } - return nil - }) - } - if gErr := g.Wait(); gErr != nil { - return nil, gErr + parentIDs[i] = new(big.Int).Sub(id, common.Big1) + blockIDs[i] = id + uint64BlockIDs[i] = id.Uint64() + if id.Cmp(highestBlockID) > 0 { + highestBlockID = id + } } + // Get the local L2 parent headers. parents, err := cli.L2.BatchHeadersByNumbers(ctxWithTimeout, parentIDs) if err != nil { return nil, err } + if len(parents) != len(ids) { + return nil, ErrInvalidLength + } for i := range ids { parentHashes[i] = parents[i].Hash() } @@ -311,7 +309,10 @@ func BatchGetBlocksProofStatus( if err != nil { return nil, err } - g, _ = errgroup.WithContext(ctxWithTimeout) + if len(transitions) != len(ids) || len(blockHeaders) != len(ids) { + return nil, ErrInvalidLength + } + g, _ := errgroup.WithContext(ctxWithTimeout) for i, transition := range transitions { // No proof on chain if transition.BlockHash == (common.Hash{}) {