Skip to content

Commit 17346cf

Browse files
fix(taiko-client): fix an issue in isBatchPreconfirmed (#19314)
1 parent 461bf65 commit 17346cf

File tree

3 files changed

+154
-51
lines changed

3 files changed

+154
-51
lines changed

packages/taiko-client/driver/chain_syncer/blob/blocks_inserter/common.go

Lines changed: 38 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import (
77
"fmt"
88
"math/big"
99

10-
"github.com/ethereum/go-ethereum"
1110
"github.com/ethereum/go-ethereum/beacon/engine"
1211
"github.com/ethereum/go-ethereum/common"
1312
consensus "github.com/ethereum/go-ethereum/consensus/taiko"
@@ -203,50 +202,49 @@ func isBatchPreconfirmed(
203202
metadata metadata.TaikoProposalMetaData,
204203
allTxs []*types.Transaction,
205204
txListBytes []byte,
205+
parent *types.Header,
206206
) (*types.Header, error) {
207-
// Get the parent block of the last block in this batch.
208-
parent, err := rpc.L2.HeaderByNumber(ctx, new(big.Int).SetUint64(metadata.Pacaya().GetLastBlockID()-1))
209-
if err != nil && !errors.Is(err, ethereum.NotFound) {
210-
return nil, fmt.Errorf("failed to get parent block: %w", err)
211-
}
212-
// If we can't find the parent block, then its not preconfirmed.
213-
if parent == nil {
214-
log.Debug("Parent block not found, batch is not preconfirmed", "batchID", metadata.Pacaya().GetBatchID())
215-
return nil, nil
216-
}
207+
// Check each block in the batch, and if the all blocks are preconfirmed, return the header of the last block.
208+
for i := 0; i < len(metadata.Pacaya().GetBlocks()); i++ {
209+
createExecutionPayloadsMetaData, anchorTx, err := assembleCreateExecutionPayloadMetaPacaya(
210+
ctx,
211+
rpc,
212+
anchorConstructor,
213+
metadata,
214+
allTxs,
215+
parent,
216+
i,
217+
)
218+
if err != nil {
219+
return nil, fmt.Errorf("failed to assemble execution payload creation metadata: %w", err)
220+
}
217221

218-
// Then we check if the last block in this batch is preconfirmed.
219-
createExecutionPayloadsMetaData, anchorTx, err := assembleCreateExecutionPayloadMetaPacaya(
220-
ctx,
221-
rpc,
222-
anchorConstructor,
223-
metadata,
224-
allTxs,
225-
parent,
226-
len(metadata.Pacaya().GetBlocks())-1,
227-
)
228-
if err != nil {
229-
return nil, fmt.Errorf("failed to assemble execution payload creation metadata: %w", err)
230-
}
222+
b, err := rlp.EncodeToBytes(append([]*types.Transaction{anchorTx}, createExecutionPayloadsMetaData.Txs...))
223+
if err != nil {
224+
return nil, fmt.Errorf("failed to RLP encode tx list: %w", err)
225+
}
231226

232-
b, err := rlp.EncodeToBytes(append([]*types.Transaction{anchorTx}, createExecutionPayloadsMetaData.Txs...))
233-
if err != nil {
234-
return nil, fmt.Errorf("failed to RLP encode tx list: %w", err)
227+
header, err := isBlockPreconfirmed(
228+
ctx,
229+
rpc,
230+
&createPayloadAndSetHeadMetaData{
231+
createExecutionPayloadsMetaData: createExecutionPayloadsMetaData,
232+
AnchorBlockID: new(big.Int).SetUint64(metadata.Pacaya().GetAnchorBlockID()),
233+
AnchorBlockHash: metadata.Pacaya().GetAnchorBlockHash(),
234+
BaseFeeConfig: metadata.Pacaya().GetBaseFeeConfig(),
235+
Parent: parent,
236+
},
237+
b,
238+
anchorTx,
239+
)
240+
if err != nil {
241+
return nil, fmt.Errorf("failed to check if block is preconfirmed: %w", err)
242+
}
243+
244+
parent = header
235245
}
236246

237-
return isBlockPreconfirmed(
238-
ctx,
239-
rpc,
240-
&createPayloadAndSetHeadMetaData{
241-
createExecutionPayloadsMetaData: createExecutionPayloadsMetaData,
242-
AnchorBlockID: new(big.Int).SetUint64(metadata.Pacaya().GetAnchorBlockID()),
243-
AnchorBlockHash: metadata.Pacaya().GetAnchorBlockHash(),
244-
BaseFeeConfig: metadata.Pacaya().GetBaseFeeConfig(),
245-
Parent: parent,
246-
},
247-
b,
248-
anchorTx,
249-
)
247+
return parent, nil
250248
}
251249

252250
// isBlockPreconfirmed checks if the block is preconfirmed.

packages/taiko-client/driver/chain_syncer/blob/blocks_inserter/pacaya.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,15 @@ func (i *BlocksInserterPacaya) InsertBlocks(
141141
// trying to fetch the last block header from L2 EE. If it is preconfirmed, we can skip the rest of the blocks,
142142
// and only update the L1Origin in L2 EE for each block.
143143
if j == 0 {
144-
lastBlockHeader, err := isBatchPreconfirmed(ctx, i.rpc, i.anchorConstructor, metadata, allTxs, txListBytes)
144+
lastBlockHeader, err := isBatchPreconfirmed(
145+
ctx,
146+
i.rpc,
147+
i.anchorConstructor,
148+
metadata,
149+
allTxs,
150+
txListBytes,
151+
parent,
152+
)
145153
if err != nil {
146154
log.Debug("Failed to check if batch is preconfirmed", "batchID", meta.GetBatchID(), "err", err)
147155
} else if lastBlockHeader != nil {

packages/taiko-client/driver/driver_test.go

Lines changed: 107 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,7 @@ func (s *DriverTestSuite) TestInsertPreconfBlocks() {
418418
s.True(res.IsSuccess())
419419

420420
// Try to insert two preconfirmation blocks
421-
s.True(s.insertPreconfBlock(s.preconfServerURL, l1Head1, l2Head2.Number.Uint64()+1).IsSuccess())
421+
s.True(s.insertPreconfBlock(s.preconfServerURL, l1Head1, l2Head2.Number.Uint64()+1, l1Head1.Time).IsSuccess())
422422
l2Head3, err := s.d.rpc.L2.BlockByNumber(context.Background(), nil)
423423
s.Nil(err)
424424

@@ -431,7 +431,7 @@ func (s *DriverTestSuite) TestInsertPreconfBlocks() {
431431
s.Equal(common.Hash{}, l1Origin.L1BlockHash)
432432
s.True(l1Origin.IsPreconfBlock())
433433

434-
s.True(s.insertPreconfBlock(s.preconfServerURL, l1Head1, l2Head2.Number.Uint64()+2).IsSuccess())
434+
s.True(s.insertPreconfBlock(s.preconfServerURL, l1Head1, l2Head2.Number.Uint64()+2, l1Head1.Time).IsSuccess())
435435
l2Head4, err := s.d.rpc.L2.BlockByNumber(context.Background(), nil)
436436
s.Nil(err)
437437

@@ -502,7 +502,7 @@ func (s *DriverTestSuite) TestInsertPreconfBlocksNotReorg() {
502502
s.True(res.IsSuccess())
503503

504504
// Try to insert two preconfirmation blocks
505-
s.True(s.insertPreconfBlock(s.preconfServerURL, l1Head1, l2Head2.Number.Uint64()+1).IsSuccess())
505+
s.True(s.insertPreconfBlock(s.preconfServerURL, l1Head1, l2Head2.Number.Uint64()+1, l1Head1.Time).IsSuccess())
506506
l2Head3, err := s.d.rpc.L2.BlockByNumber(context.Background(), nil)
507507
s.Nil(err)
508508

@@ -515,14 +515,18 @@ func (s *DriverTestSuite) TestInsertPreconfBlocksNotReorg() {
515515
s.Equal(common.Hash{}, l1Origin.L1BlockHash)
516516
s.True(l1Origin.IsPreconfBlock())
517517

518-
s.True(s.insertPreconfBlock(s.preconfServerURL, l1Head1, l2Head2.Number.Uint64()+2).IsSuccess())
518+
s.True(s.insertPreconfBlock(s.preconfServerURL, l1Head1, l2Head2.Number.Uint64()+2, l1Head1.Time).IsSuccess())
519519
l2Head4, err := s.d.rpc.L2.BlockByNumber(context.Background(), nil)
520520
s.Nil(err)
521521
s.Equal(l2Head3.Number().Uint64()+1, l2Head4.Number().Uint64())
522522
s.Equal(2, len(l2Head4.Transactions()))
523523

524524
// Propose two same L2 blocks in a batch
525-
s.proposePreconfBatch([]*types.Block{l2Head3, l2Head4}, []*types.Header{l1Head1, l1Head1})
525+
s.proposePreconfBatch(
526+
[]*types.Block{l2Head3, l2Head4},
527+
[]*types.Header{l1Head1, l1Head1},
528+
[]uint8{0, 0},
529+
)
526530

527531
l2Head5, err := s.d.rpc.L2.BlockByNumber(context.Background(), nil)
528532
s.Nil(err)
@@ -607,6 +611,93 @@ func (s *DriverTestSuite) TestOnUnsafeL2Payload() {
607611
s.Equal(anchorTx.Hash(), l2Head2.Transactions()[0].Hash())
608612
}
609613

614+
func (s *DriverTestSuite) TestInsertPreconfBlocksWithReorg() {
615+
l2Head1, err := s.d.rpc.L2.HeaderByNumber(context.Background(), nil)
616+
s.Nil(err)
617+
618+
s.Nil(s.d.ChainSyncer().BlobSyncer().ProcessL1Blocks(context.Background()))
619+
620+
// Propose valid L2 blocks to make the L2 fork into Pacaya fork.
621+
s.ForkIntoPacaya(s.p, s.d.ChainSyncer().BlobSyncer())
622+
623+
l2Head2, err := s.d.rpc.L2.HeaderByNumber(context.Background(), nil)
624+
s.Nil(err)
625+
626+
l1Head1, err := s.d.rpc.L1.HeaderByNumber(context.Background(), nil)
627+
s.Nil(err)
628+
629+
s.GreaterOrEqual(l2Head2.Number.Uint64(), l2Head1.Number.Uint64())
630+
631+
res, err := resty.New().R().Get(s.preconfServerURL.String() + "/healthz")
632+
s.Nil(err)
633+
s.True(res.IsSuccess())
634+
635+
// Try to insert four preconfirmation blocks
636+
var (
637+
preconfBlocksNum = 4
638+
preconfBlocks = make([]*types.Block, preconfBlocksNum)
639+
)
640+
for i := 0; i < preconfBlocksNum; i++ {
641+
s.True(s.insertPreconfBlock(
642+
s.preconfServerURL,
643+
l1Head1,
644+
l2Head2.Number.Uint64()+1+uint64(i),
645+
l1Head1.Time+uint64(preconfBlocksNum),
646+
).IsSuccess())
647+
head, err := s.d.rpc.L2.BlockByNumber(context.Background(), nil)
648+
s.Nil(err)
649+
650+
s.Equal(2, len(head.Transactions()))
651+
preconfBlocks[i] = head
652+
653+
l1Origin, err := s.RPCClient.L2.L1OriginByID(
654+
context.Background(),
655+
new(big.Int).SetUint64(l2Head2.Number.Uint64()+1+uint64(i)),
656+
)
657+
s.Nil(err)
658+
s.Equal(head.Number().Uint64(), l1Origin.BlockID.Uint64())
659+
s.Equal(head.Hash(), l1Origin.L2BlockHash)
660+
s.Equal(common.Hash{}, l1Origin.L1BlockHash)
661+
s.True(l1Origin.IsPreconfBlock())
662+
663+
headL1Origin, err := s.RPCClient.L2.HeadL1Origin(context.Background())
664+
s.Nil(err)
665+
s.Equal(l2Head2.Number, headL1Origin.BlockID)
666+
s.Equal(l2Head2.Hash(), headL1Origin.L2BlockHash)
667+
s.False(headL1Origin.IsPreconfBlock())
668+
}
669+
670+
// Propose three same L2 blocks in a batch
671+
s.proposePreconfBatch(
672+
preconfBlocks,
673+
[]*types.Header{l1Head1, l1Head1, l1Head1, l1Head1},
674+
[]uint8{0, 1, 0, 0},
675+
)
676+
677+
l2Head3, err := s.d.rpc.L2.BlockByNumber(context.Background(), nil)
678+
s.Nil(err)
679+
s.Equal(l2Head3.Number().Uint64(), preconfBlocks[len(preconfBlocks)-1].Number().Uint64())
680+
s.NotEqual(l2Head3.Hash(), preconfBlocks[len(preconfBlocks)-1].Hash())
681+
s.Equal(2, len(l2Head3.Transactions()))
682+
683+
l1Origin2, err := s.RPCClient.L2.L1OriginByID(
684+
context.Background(),
685+
new(big.Int).SetUint64(l2Head2.Number.Uint64()+uint64(preconfBlocksNum)),
686+
)
687+
s.Nil(err)
688+
s.Equal(l2Head3.Number().Uint64(), l1Origin2.BlockID.Uint64())
689+
s.Equal(l2Head3.Hash(), l1Origin2.L2BlockHash)
690+
s.Equal(l2Head3.Hash(), l1Origin2.L2BlockHash)
691+
s.NotEqual(common.Hash{}, l1Origin2.L1BlockHash)
692+
s.False(l1Origin2.IsPreconfBlock())
693+
694+
canonicalL1Origin, err := s.RPCClient.L2.HeadL1Origin(context.Background())
695+
s.Nil(err)
696+
s.Equal(l1Origin2, canonicalL1Origin)
697+
s.Equal(l2Head3.Number().Uint64(), canonicalL1Origin.BlockID.Uint64())
698+
s.Equal(l2Head3.Hash(), canonicalL1Origin.L2BlockHash)
699+
}
700+
610701
func (s *DriverTestSuite) TestOnUnsafeL2PayloadWithInvalidPayload() {
611702
s.ForkIntoPacaya(s.p, s.d.ChainSyncer().BlobSyncer())
612703
// Propose some valid L2 blocks
@@ -934,7 +1025,11 @@ func (s *DriverTestSuite) TestOnUnsafeL2PayloadWithMissingAncients() {
9341025
s.Equal(l2Head2.Number.Uint64(), l2Head5.Number().Uint64())
9351026
}
9361027

937-
func (s *DriverTestSuite) proposePreconfBatch(blocks []*types.Block, anchoredL1Blocks []*types.Header) {
1028+
func (s *DriverTestSuite) proposePreconfBatch(
1029+
blocks []*types.Block,
1030+
anchoredL1Blocks []*types.Header,
1031+
timeShifts []uint8,
1032+
) {
9381033
var (
9391034
to = &s.p.TaikoL1Address
9401035
proposer = crypto.PubkeyToAddress(s.p.L1ProposerPrivKey.PublicKey)
@@ -950,12 +1045,13 @@ func (s *DriverTestSuite) proposePreconfBatch(blocks []*types.Block, anchoredL1B
9501045

9511046
s.NotZero(len(blocks))
9521047
s.Equal(len(blocks), len(anchoredL1Blocks))
1048+
s.Equal(len(blocks), len(timeShifts))
9531049

954-
for _, b := range blocks {
1050+
for i, b := range blocks {
9551051
allTxs = append(allTxs, b.Transactions()[1:]...)
9561052
blockParams = append(blockParams, pacayaBindings.ITaikoInboxBlockParams{
9571053
NumTransactions: uint16(b.Transactions()[1:].Len()),
958-
TimeShift: 0,
1054+
TimeShift: timeShifts[i],
9591055
})
9601056
}
9611057

@@ -1070,6 +1166,7 @@ func (s *DriverTestSuite) insertPreconfBlock(
10701166
url *url.URL,
10711167
anchoredL1Block *types.Header,
10721168
l2BlockID uint64,
1169+
timestamp uint64,
10731170
) *resty.Response {
10741171
preconferPrivKey, err := crypto.ToECDSA(common.FromHex(os.Getenv("L1_PROPOSER_PRIVATE_KEY")))
10751172
s.Nil(err)
@@ -1104,7 +1201,7 @@ func (s *DriverTestSuite) insertPreconfBlock(
11041201
parent,
11051202
true,
11061203
s.d.protocolConfig.BaseFeeConfig(),
1107-
anchoredL1Block.Time,
1204+
timestamp,
11081205
)
11091206
s.Nil(err)
11101207

@@ -1136,7 +1233,7 @@ func (s *DriverTestSuite) insertPreconfBlock(
11361233
Number: l2BlockID,
11371234
GasLimit: uint64(s.d.protocolConfig.BlockMaxGasLimit() + uint32(consensus.AnchorV3GasLimit)),
11381235
ExtraData: hexutil.Bytes(extraData[:]),
1139-
Timestamp: anchoredL1Block.Time,
1236+
Timestamp: timestamp,
11401237
Transactions: b,
11411238
BaseFeePerGas: baseFee.Uint64(),
11421239
},

0 commit comments

Comments
 (0)