Skip to content

Commit 883a356

Browse files
feat(taiko-client): introduce BuildPayloadArgsID for L1Origin (#19444)
1 parent d12fd47 commit 883a356

File tree

4 files changed

+79
-88
lines changed

4 files changed

+79
-88
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ require (
309309
rsc.io/tmplfunc v0.0.3 // indirect
310310
)
311311

312-
replace github.com/ethereum/go-ethereum v1.15.5 => github.com/taikoxyz/taiko-geth v0.0.0-20250422211912-3a4f3775cc30
312+
replace github.com/ethereum/go-ethereum v1.15.5 => github.com/taikoxyz/taiko-geth v1.15.1-0.20250513061338-4dedd6e4a405
313313

314314
replace github.com/ethereum-optimism/optimism v1.7.4 => github.com/taikoxyz/optimism v0.0.0-20250407113505-a4338a4857e6
315315

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -878,8 +878,8 @@ github.com/taikoxyz/hive v0.0.0-20240827015317-405b241dd082 h1:ymZR+Y88LOnA8i3Ke
878878
github.com/taikoxyz/hive v0.0.0-20240827015317-405b241dd082/go.mod h1:RHnIu3EFehrWX3JhFAMQSXD5uz7l0xaNroTzXrap7EQ=
879879
github.com/taikoxyz/optimism v0.0.0-20250407113505-a4338a4857e6 h1:TZqB0xhP6eqTbuPSnMYB6md6EtGoYoYCMAK/v9HV1YM=
880880
github.com/taikoxyz/optimism v0.0.0-20250407113505-a4338a4857e6/go.mod h1:V0VCkKtCzuaJH6qcL75SRcbdlakM9LhurMEJUhO6VXA=
881-
github.com/taikoxyz/taiko-geth v0.0.0-20250422211912-3a4f3775cc30 h1:zduJWfvVFUMoSiBQ2SjlmhckQY3X+XkdtHitooaHpKg=
882-
github.com/taikoxyz/taiko-geth v0.0.0-20250422211912-3a4f3775cc30/go.mod h1:1LG2LnMOx2yPRHR/S+xuipXH29vPr6BIH6GElD8N/fo=
881+
github.com/taikoxyz/taiko-geth v1.15.1-0.20250513061338-4dedd6e4a405 h1:aOHNO/3XeBpwRv9N+CmHRfv9y5nuTikdWdn7AWg421k=
882+
github.com/taikoxyz/taiko-geth v1.15.1-0.20250513061338-4dedd6e4a405/go.mod h1:1LG2LnMOx2yPRHR/S+xuipXH29vPr6BIH6GElD8N/fo=
883883
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
884884
github.com/testcontainers/testcontainers-go v0.35.0 h1:uADsZpTKFAtp8SLK+hMwSaa+X+JiERHtd4sQAFmXeMo=
885885
github.com/testcontainers/testcontainers-go v0.35.0/go.mod h1:oEVBj5zrfJTrgjwONs1SsRbnBtH9OKl+IGl3UMcr2B4=

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

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

10+
"github.com/ethereum/go-ethereum"
1011
"github.com/ethereum/go-ethereum/beacon/engine"
1112
"github.com/ethereum/go-ethereum/common"
1213
consensus "github.com/ethereum/go-ethereum/consensus/taiko"
@@ -54,6 +55,21 @@ func createPayloadAndSetHead(
5455
meta.GasLimit += consensus.AnchorGasLimit
5556
}
5657

58+
// Update execution payload id for the L1 origin.
59+
var (
60+
txListHash = crypto.Keccak256Hash(txListBytes)
61+
args = &miner.BuildPayloadArgs{
62+
Parent: meta.ParentHash,
63+
Timestamp: meta.Timestamp,
64+
FeeRecipient: meta.SuggestedFeeRecipient,
65+
Random: meta.Difficulty,
66+
Withdrawals: make([]*types.Withdrawal, 0),
67+
Version: engine.PayloadV2,
68+
TxListHash: &txListHash,
69+
}
70+
)
71+
meta.L1Origin.BuildPayloadArgsID = args.Id()
72+
5773
// Create a new execution payload and set the chain head.
5874
return createExecutionPayloadsAndSetHead(ctx, rpc, meta.createExecutionPayloadsMetaData, txListBytes)
5975
}
@@ -193,9 +209,9 @@ func createExecutionPayloads(
193209
return payload, nil
194210
}
195211

196-
// isBatchPreconfirmed checks if all blocks in the given batch are preconfirmed,
197-
// and returns the header of the last block in the batch if it is preconfirmed.
198-
func isBatchPreconfirmed(
212+
// isKnownCanonicalBatch checks if all blocks in the given batch are in the canonical chain already.,
213+
// and returns the header of the last block in the batch if it is.
214+
func isKnownCanonicalBatch(
199215
ctx context.Context,
200216
rpc *rpc.Client,
201217
anchorConstructor *anchorTxConstructor.AnchorTxConstructor,
@@ -235,7 +251,7 @@ func isBatchPreconfirmed(
235251
return fmt.Errorf("failed to RLP encode tx list: %w", err)
236252
}
237253

238-
if headers[i], err = isBlockPreconfirmed(
254+
if headers[i], err = isKnownCanonicalBlock(
239255
ctx,
240256
rpc,
241257
&createPayloadAndSetHeadMetaData{
@@ -258,8 +274,8 @@ func isBatchPreconfirmed(
258274
return headers[len(headers)-1], g.Wait()
259275
}
260276

261-
// isBlockPreconfirmed checks if the block is preconfirmed.
262-
func isBlockPreconfirmed(
277+
// isKnownCanonicalBlock checks if the block is in canonical chain already.
278+
func isKnownCanonicalBlock(
263279
ctx context.Context,
264280
rpc *rpc.Client,
265281
meta *createPayloadAndSetHeadMetaData,
@@ -280,81 +296,31 @@ func isBlockPreconfirmed(
280296
txListHash = crypto.Keccak256Hash(txListBytes[:])
281297
args = &miner.BuildPayloadArgs{
282298
Parent: meta.Parent.Hash(),
283-
Timestamp: block.Time(),
284-
FeeRecipient: block.Coinbase(),
285-
Random: block.MixDigest(),
299+
Timestamp: meta.Timestamp,
300+
FeeRecipient: meta.SuggestedFeeRecipient,
301+
Random: meta.Difficulty,
286302
Withdrawals: make([]*types.Withdrawal, 0),
287303
Version: engine.PayloadV2,
288304
TxListHash: &txListHash,
289305
}
290306
id = args.Id()
291307
)
292-
executableData, err := rpc.L2Engine.GetPayload(ctx, &id)
293-
if err != nil {
294-
return nil, fmt.Errorf("failed to get payload: %w", err)
295-
}
296-
297-
defer func() {
298-
if err != nil {
299-
log.Warn("Invalid preconfirmed block", "blockID", blockID, "coinbase", executableData.FeeRecipient, "reason", err)
300-
}
301-
}()
302-
303-
if executableData.BlockHash != block.Hash() {
304-
err = fmt.Errorf("block hash mismatch: %s != %s", executableData.BlockHash, block.Hash())
305-
return nil, err
306-
}
307-
if block.ParentHash() != meta.ParentHash {
308-
err = fmt.Errorf("parent hash mismatch: %s != %s", block.ParentHash(), meta.ParentHash)
309-
return nil, err
310-
}
311-
if block.Transactions().Len() == 0 {
312-
err = errors.New("transactions list is empty")
313-
return nil, err
314-
}
315-
if block.Transactions()[0].Hash() != anchorTx.Hash() {
316-
err = fmt.Errorf("anchor transaction mismatch: %s != %s", block.Transactions()[0].Hash(), anchorTx.Hash())
317-
return nil, err
318-
}
319-
if block.UncleHash() != types.EmptyUncleHash {
320-
err = fmt.Errorf("uncle hash mismatch: %s != %s", block.UncleHash(), types.EmptyUncleHash)
321-
return nil, err
308+
l1Origin, err := rpc.L2.L1OriginByID(ctx, blockID)
309+
if err != nil && !errors.Is(err, ethereum.NotFound) {
310+
return nil, fmt.Errorf("failed to get L1Origin by ID %d: %w", blockID, err)
322311
}
323-
if block.Coinbase() != meta.SuggestedFeeRecipient {
324-
err = fmt.Errorf("coinbase mismatch: %s != %s", block.Coinbase(), meta.SuggestedFeeRecipient)
325-
return nil, err
326-
}
327-
if block.Difficulty().Cmp(common.Big0) != 0 {
328-
err = fmt.Errorf("difficulty mismatch: %s != 0", block.Difficulty())
329-
return nil, err
312+
// If L1Origin is not found, it means this block is synced from beacon sync.
313+
if l1Origin == nil {
314+
return nil, fmt.Errorf("L1Origin not found by ID %d", blockID)
330315
}
331-
if block.MixDigest() != meta.Difficulty {
332-
err = fmt.Errorf("mixDigest mismatch: %s != %s", block.MixDigest(), meta.Difficulty)
333-
return nil, err
334-
}
335-
if block.Number().Uint64() != meta.BlockID.Uint64() {
336-
err = fmt.Errorf("block number mismatch: %d != %d", block.Number(), meta.BlockID)
337-
return nil, err
338-
}
339-
if block.GasLimit() != meta.GasLimit+consensus.AnchorV3GasLimit {
340-
err = fmt.Errorf("gas limit mismatch: %d != %d", block.GasLimit(), meta.GasLimit+consensus.AnchorV3GasLimit)
341-
return nil, err
342-
}
343-
if block.Time() != meta.Timestamp {
344-
err = fmt.Errorf("timestamp mismatch: %d != %d", block.Time(), meta.Timestamp)
345-
return nil, err
346-
}
347-
if !bytes.Equal(block.Extra(), meta.ExtraData) {
348-
err = fmt.Errorf("extra data mismatch: %s != %s", block.Extra(), meta.ExtraData)
349-
return nil, err
350-
}
351-
if block.BaseFee().Cmp(meta.BaseFee) != 0 {
352-
err = fmt.Errorf("base fee mismatch: %s != %s", block.BaseFee(), meta.BaseFee)
353-
return nil, err
354-
}
355-
if block.Withdrawals().Len() != 0 {
356-
err = fmt.Errorf("withdrawals mismatch: %d != 0", block.Withdrawals().Len())
357-
return nil, err
316+
// If the payload ID matches, it means this block is already in the canonical chain.
317+
if l1Origin.BuildPayloadArgsID != [8]byte{} && !bytes.Equal(l1Origin.BuildPayloadArgsID[:], id[:]) {
318+
return nil, fmt.Errorf(
319+
"payload ID for block %d mismatch, l1Origin payload id: %s, current payload id %s",
320+
blockID,
321+
engine.PayloadID(l1Origin.BuildPayloadArgsID),
322+
id,
323+
)
358324
}
359325

360326
return block.Header(), nil
@@ -460,6 +426,7 @@ func assembleCreateExecutionPayloadMetaPacaya(
460426
}, anchorTx, nil
461427
}
462428

429+
// updateL1OriginForBatch updates the L1 origin for the given batch of blocks.
463430
func updateL1OriginForBatch(
464431
ctx context.Context,
465432
rpc *rpc.Client,
@@ -489,9 +456,19 @@ func updateL1OriginForBatch(
489456
L1BlockHeight: meta.GetRawBlockHeight(),
490457
L1BlockHash: meta.GetRawBlockHash(),
491458
}
459+
// Fetch the original L1Origin to get the BuildPayloadArgsID.
460+
originalL1Origin, err := rpc.L2.L1OriginByID(ctx, blockID)
461+
if err != nil && !errors.Is(err, ethereum.NotFound) {
462+
return fmt.Errorf("failed to get L1Origin by ID %d: %w", blockID, err)
463+
}
464+
// If L1Origin is not found, it means this block is synced from beacon sync,
465+
// and we also won't set the `BuildPayloadArgsID` value.
466+
if originalL1Origin != nil {
467+
l1Origin.BuildPayloadArgsID = originalL1Origin.BuildPayloadArgsID
468+
}
492469

493470
if _, err := rpc.L2Engine.UpdateL1Origin(ctx, l1Origin); err != nil {
494-
return fmt.Errorf("failed to update L1 origin: %w", err)
471+
return fmt.Errorf("failed to update L1Origin: %w", err)
495472
}
496473

497474
// If this is the most recent block, update the HeadL1Origin.

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

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ import (
1313
"github.com/ethereum/go-ethereum/common"
1414
"github.com/ethereum/go-ethereum/core/rawdb"
1515
"github.com/ethereum/go-ethereum/core/types"
16+
"github.com/ethereum/go-ethereum/crypto"
1617
"github.com/ethereum/go-ethereum/log"
18+
"github.com/ethereum/go-ethereum/miner"
1719
"github.com/holiman/uint256"
1820

1921
"github.com/taikoxyz/taiko-mono/packages/taiko-client/bindings/metadata"
@@ -138,11 +140,11 @@ func (i *BlocksInserterPacaya) InsertBlocks(
138140
"beaconSyncTriggered", i.progressTracker.Triggered(),
139141
)
140142

141-
// If this is the first block in the batch, we check if the whole batch has been preconfirmed by
142-
// trying to fetch the last block header from L2 EE. If it is preconfirmed, we can skip the rest of the blocks,
143-
// and only update the L1Origin in L2 EE for each block.
143+
// If this is the first block in the batch, we check if the whole batch has been inserted by
144+
// trying to fetch the last block header from L2 EE. If it is known in canonical,
145+
// we can skip the rest of the blocks, and only update the L1Origin in L2 EE for each block.
144146
if j == 0 {
145-
lastBlockHeader, err := isBatchPreconfirmed(
147+
lastBlockHeader, err := isKnownCanonicalBatch(
146148
ctx,
147149
i.rpc,
148150
i.anchorConstructor,
@@ -152,10 +154,10 @@ func (i *BlocksInserterPacaya) InsertBlocks(
152154
parent,
153155
)
154156
if err != nil {
155-
log.Debug("Failed to check if batch is preconfirmed", "batchID", meta.GetBatchID(), "err", err)
157+
log.Debug("Failed to check if batch is in canonical chain already", "batchID", meta.GetBatchID(), "err", err)
156158
} else if lastBlockHeader != nil {
157159
log.Info(
158-
"🧬 The batch is preconfirmed",
160+
"🧬 Known batch in canonical chain",
159161
"batchID", meta.GetBatchID(),
160162
"lastBlockID", meta.GetLastBlockID(),
161163
"lastBlockHash", lastBlockHeader.Hash(),
@@ -315,7 +317,18 @@ func (i *BlocksInserterPacaya) insertPreconfBlockFromExecutionPayload(
315317
if executableData.Transactions[0], err = utils.DecompressPacaya(executableData.Transactions[0]); err != nil {
316318
return nil, fmt.Errorf("failed to decompress transactions list bytes: %w", err)
317319
}
318-
320+
var (
321+
txListHash = crypto.Keccak256Hash(executableData.Transactions[0])
322+
args = &miner.BuildPayloadArgs{
323+
Parent: executableData.ParentHash,
324+
Timestamp: uint64(executableData.Timestamp),
325+
FeeRecipient: executableData.FeeRecipient,
326+
Random: common.Hash(executableData.PrevRandao),
327+
Withdrawals: make([]*types.Withdrawal, 0),
328+
Version: engine.PayloadV2,
329+
TxListHash: &txListHash,
330+
}
331+
)
319332
var u256BaseFee = uint256.Int(executableData.BaseFeePerGas)
320333
payload, err := createExecutionPayloadsAndSetHead(
321334
ctx,
@@ -329,10 +342,11 @@ func (i *BlocksInserterPacaya) insertPreconfBlockFromExecutionPayload(
329342
Timestamp: uint64(executableData.Timestamp),
330343
ParentHash: executableData.ParentHash,
331344
L1Origin: &rawdb.L1Origin{
332-
BlockID: new(big.Int).SetUint64(uint64(executableData.BlockNumber)),
333-
L2BlockHash: common.Hash{}, // Will be set by taiko-geth.
334-
L1BlockHeight: nil,
335-
L1BlockHash: common.Hash{},
345+
BlockID: new(big.Int).SetUint64(uint64(executableData.BlockNumber)),
346+
L2BlockHash: common.Hash{}, // Will be set by taiko-geth.
347+
L1BlockHeight: nil,
348+
L1BlockHash: common.Hash{},
349+
BuildPayloadArgsID: args.Id(),
336350
},
337351
BaseFee: u256BaseFee.ToBig(),
338352
Withdrawals: make([]*types.Withdrawal, 0),

0 commit comments

Comments
 (0)