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

feat(taiko-client): check if the block is preconfirmed before calling setHead #18864

Merged
merged 16 commits into from
Feb 5, 2025
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"packages/relayer": "0.12.0",
"packages/snaefell-ui": "1.1.0",
"packages/supplementary-contracts": "1.0.0",
"packages/taiko-client": "0.43.1",
"packages/taiko-client": "1.0.1",
"packages/taikoon-ui": "1.3.0",
"packages/ui-lib": "1.0.0"
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ require (
sigs.k8s.io/yaml v1.3.0 // indirect
)

replace github.com/ethereum/go-ethereum v1.14.11 => github.com/taikoxyz/taiko-geth v1.12.1-0.20250204084657-54ca2198a63b
replace github.com/ethereum/go-ethereum v1.14.11 => github.com/taikoxyz/taiko-geth v1.12.1-0.20250204160805-e2da82206df3

replace github.com/ethereum-optimism/optimism v1.7.4 => github.com/taikoxyz/optimism v0.0.0-20250128202721-1b986d622e1a

Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -888,8 +888,8 @@ github.com/taikoxyz/hive v0.0.0-20240827015317-405b241dd082 h1:ymZR+Y88LOnA8i3Ke
github.com/taikoxyz/hive v0.0.0-20240827015317-405b241dd082/go.mod h1:RHnIu3EFehrWX3JhFAMQSXD5uz7l0xaNroTzXrap7EQ=
github.com/taikoxyz/optimism v0.0.0-20250128202721-1b986d622e1a h1:33/0g4tyyoxFoengwPv6sEseEcEGITqfXbCyruSyXxY=
github.com/taikoxyz/optimism v0.0.0-20250128202721-1b986d622e1a/go.mod h1:V0VCkKtCzuaJH6qcL75SRcbdlakM9LhurMEJUhO6VXA=
github.com/taikoxyz/taiko-geth v1.12.1-0.20250204084657-54ca2198a63b h1:KEXW+q9KzW7VPAiPvxbGrY3Ian30tPCVmjgkHpNDeZc=
github.com/taikoxyz/taiko-geth v1.12.1-0.20250204084657-54ca2198a63b/go.mod h1:+l/fr42Mma+xBnhefL/+z11/hcmJ2egl+ScIVPjhc7E=
github.com/taikoxyz/taiko-geth v1.12.1-0.20250204160805-e2da82206df3 h1:F6I7sOgOT2YY0Rqf6dkw7axM6S6+YTCMrSlOZf3g8iU=
github.com/taikoxyz/taiko-geth v1.12.1-0.20250204160805-e2da82206df3/go.mod h1:+l/fr42Mma+xBnhefL/+z11/hcmJ2egl+ScIVPjhc7E=
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
github.com/testcontainers/testcontainers-go v0.35.0 h1:uADsZpTKFAtp8SLK+hMwSaa+X+JiERHtd4sQAFmXeMo=
github.com/testcontainers/testcontainers-go v0.35.0/go.mod h1:oEVBj5zrfJTrgjwONs1SsRbnBtH9OKl+IGl3UMcr2B4=
Expand Down
2 changes: 1 addition & 1 deletion packages/taiko-client/bindings/pacaya/.githead
Original file line number Diff line number Diff line change
@@ -1 +1 @@
f5938d4b6e54069d11df6b40ede3ad83012cf0e6
1713be26d6226695f393da883a8cf22d4152dcc9
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@ import (
"context"
"errors"
"fmt"
"math/big"

"github.com/ethereum/go-ethereum/beacon/engine"
"github.com/ethereum/go-ethereum/common"
consensus "github.com/ethereum/go-ethereum/consensus/taiko"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/miner"
"github.com/ethereum/go-ethereum/rlp"

"github.com/taikoxyz/taiko-mono/packages/taiko-client/bindings/encoding"
"github.com/taikoxyz/taiko-mono/packages/taiko-client/pkg/rpc"
"github.com/taikoxyz/taiko-mono/packages/taiko-client/pkg/utils"
)
Expand All @@ -31,6 +34,36 @@ func createPayloadAndSetHead(
"l1Origin", meta.L1Origin,
)

// If the Pacaya block is preconfirmed, we don't need to insert it again.
if meta.BlockID.Cmp(new(big.Int).SetUint64(rpc.PacayaClients.ForkHeight)) >= 0 {
header, err := isBlockPreconfirmed(ctx, rpc, meta)
if err != nil {
log.Debug("Failed to check if the block is preconfirmed", "error", err)
YoGhurt111 marked this conversation as resolved.
Show resolved Hide resolved
} else if header != nil {
// Update the l1Origin and headL1Origin cursor for that preconfirmed block.
meta.L1Origin.L2BlockHash = header.Hash()
if _, err := rpc.L2.UpdateL1Origin(ctx, meta.L1Origin); err != nil {
return nil, fmt.Errorf("failed to update L1 origin: %w", err)
}
if _, err := rpc.L2.SetHeadL1Origin(ctx, meta.L1Origin.BlockID); err != nil {
return nil, fmt.Errorf("failed to write head L1 origin: %w", err)
}

log.Info(
"🧬 The block is preconfirmed",
"blockID", meta.BlockID,
"hash", header.Hash(),
"coinbase", header.Coinbase,
"timestamp", header.Time,
"anchorBlockID", meta.AnchorBlockID,
"anchorBlockHash", meta.AnchorBlockHash,
"baseFee", utils.WeiToEther(header.BaseFee),
)

return encoding.ToExecutableData(header), nil
}
}

payload, err := createExecutionPayloads(
ctx,
rpc,
Expand All @@ -41,21 +74,19 @@ func createPayloadAndSetHead(
return nil, fmt.Errorf("failed to create execution payloads: %w", err)
}

var (
lastVerifiedBlockHash common.Hash
)
var lastVerifiedBlockHash common.Hash
lastVerifiedTS, err := rpc.GetLastVerifiedTransitionPacaya(ctx)
if err != nil {
lastVerifiedBlockInfo, err := rpc.GetLastVerifiedBlockOntake(ctx)
if err != nil {
return nil, fmt.Errorf("failed to fetch last verified block: %w", err)
}

if payload.Number > lastVerifiedBlockInfo.BlockId {
if meta.BlockID.Uint64() > lastVerifiedBlockInfo.BlockId {
lastVerifiedBlockHash = lastVerifiedBlockInfo.BlockHash
}
} else {
if payload.Number > lastVerifiedTS.BlockId {
if meta.BlockID.Uint64() > lastVerifiedTS.BlockId {
lastVerifiedBlockHash = lastVerifiedTS.Ts.BlockHash
}
}
Expand Down Expand Up @@ -93,7 +124,6 @@ func createExecutionPayloads(
return nil, err
}

fc := &engine.ForkchoiceStateV1{HeadBlockHash: meta.ParentHash}
attributes := &engine.PayloadAttributes{
Timestamp: meta.Timestamp,
Random: meta.Difficulty,
Expand Down Expand Up @@ -128,7 +158,11 @@ func createExecutionPayloads(
)

// Step 1, prepare a payload
fcRes, err := rpc.L2Engine.ForkchoiceUpdate(ctx, fc, attributes)
fcRes, err := rpc.L2Engine.ForkchoiceUpdate(
ctx,
&engine.ForkchoiceStateV1{HeadBlockHash: meta.ParentHash},
attributes,
)
if err != nil {
return nil, fmt.Errorf("failed to update fork choice: %w", err)
}
Expand Down Expand Up @@ -168,3 +202,42 @@ func createExecutionPayloads(

return payload, nil
}

// isBlockPreconfirmed checks if the block is preconfirmed.
func isBlockPreconfirmed(
ctx context.Context,
rpc *rpc.Client,
meta *createPayloadAndSetHeadMetaData,
) (*types.Header, error) {
var blockID = new(big.Int).Add(meta.Parent.Number, common.Big1)
header, err := rpc.L2.HeaderByNumber(ctx, blockID)
if err != nil {
return nil, fmt.Errorf("failed to get header by number %d: %w", blockID, err)
}

if header == nil {
return nil, fmt.Errorf("header not found for block number %d", blockID)
}

var (
args = &miner.BuildPayloadArgs{
Parent: meta.Parent.Hash(),
Timestamp: header.Time,
FeeRecipient: header.Coinbase,
Random: header.MixDigest,
Withdrawals: make([]*types.Withdrawal, 0),
Version: engine.PayloadV2,
}
id = args.Id()
)
executableData, err := rpc.L2Engine.GetPayload(ctx, &id)
if err != nil {
return nil, fmt.Errorf("failed to get payload: %w", err)
}

if executableData.BlockHash == header.Hash() {
return header, nil
}

return nil, nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ func (i *BlocksInserterPacaya) InsertBlocks(
"blockID", blockID,
"hash", lastPayloadData.BlockHash,
"transactions", len(lastPayloadData.Transactions),
"timestamp", lastPayloadData.Timestamp,
"baseFee", utils.WeiToGWei(lastPayloadData.BaseFeePerGas),
"withdrawals", len(lastPayloadData.Withdrawals),
"batchID", meta.GetBatchID(),
Expand Down
1 change: 1 addition & 0 deletions packages/taiko-client/driver/chain_syncer/blob/syncer.go
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,7 @@ func (s *Syncer) onBlockProposed(
"l1Hash", meta.GetRawBlockHash(),
"batchID", meta.Pacaya().GetBatchID(),
"lastBlockID", lastBlockID,
"lastTimestamp", meta.Pacaya().GetLastBlockTimestamp(),
"blocks", len(meta.Pacaya().GetBlocks()),
)
if err := s.blocksInserterPacaya.InsertBlocks(ctx, meta, tx, endIter); err != nil {
Expand Down
120 changes: 116 additions & 4 deletions packages/taiko-client/driver/driver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"testing"
"time"

"github.com/cenkalti/backoff"
"github.com/ethereum-optimism/optimism/op-service/txmgr"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
Expand All @@ -23,10 +24,12 @@ import (
"github.com/stretchr/testify/suite"

"github.com/taikoxyz/taiko-mono/packages/taiko-client/bindings/encoding"
pacayaBindings "github.com/taikoxyz/taiko-mono/packages/taiko-client/bindings/pacaya"
preconfblocks "github.com/taikoxyz/taiko-mono/packages/taiko-client/driver/preconf_blocks"
"github.com/taikoxyz/taiko-mono/packages/taiko-client/internal/testutils"
"github.com/taikoxyz/taiko-mono/packages/taiko-client/pkg/jwt"
"github.com/taikoxyz/taiko-mono/packages/taiko-client/pkg/rpc"
"github.com/taikoxyz/taiko-mono/packages/taiko-client/pkg/utils"
"github.com/taikoxyz/taiko-mono/packages/taiko-client/proposer"
)

Expand Down Expand Up @@ -387,14 +390,14 @@ func (s *DriverTestSuite) TestInsertPreconfBlocks() {
// Propose 3 valid L2 blocks
s.ProposeAndInsertEmptyBlocks(s.p, s.d.ChainSyncer().BlobSyncer())

l2Head6, err := s.d.rpc.L2.BlockByNumber(context.Background(), l2Head3.Number())
l2Head6, err := s.d.rpc.L2.BlockByNumber(context.Background(), nil)
s.Nil(err)
s.Equal(l2Head3.Number().Uint64(), l2Head6.Number().Uint64())
s.Equal(l2Head3.Number().Uint64()+2, l2Head6.Number().Uint64())
s.Equal(1, len(l2Head6.Transactions()))

l1Origin3, err := s.RPCClient.L2.L1OriginByID(context.Background(), l2Head6.Number())
s.Nil(err)
s.Equal(l2Head3.Number().Uint64(), l1Origin3.BlockID.Uint64())
s.Equal(l2Head3.Number().Uint64()+2, l1Origin3.BlockID.Uint64())
s.Equal(l2Head6.Hash(), l1Origin3.L2BlockHash)
s.NotZero(l1Origin3.L1BlockHeight.Uint64())
s.NotEmpty(l1Origin3.L1BlockHash)
Expand Down Expand Up @@ -445,7 +448,7 @@ func (s *DriverTestSuite) insertPreconfBlock(
FeeRecipient: preconferAddress,
Number: l2BlockID,
GasLimit: gasLimit,
Timestamp: uint64(time.Now().Unix()),
Timestamp: anchoredL1Block.Time,
Transactions: b,
},
AnchorBlockID: anchoredL1Block.Number.Uint64(),
Expand Down Expand Up @@ -473,6 +476,115 @@ func (s *DriverTestSuite) insertPreconfBlock(
return res
}

func (s *DriverTestSuite) TestInsertPreconfBlocksNotReorg() {
var (
port = uint64(testutils.RandomPort())
err error
)
s.d.preconfBlockServer, err = preconfblocks.New(
"*", nil, s.d.ChainSyncer().BlobSyncer().BlocksInserterPacaya(), s.RPCClient, true, nil, nil,
)
s.Nil(err)
go func() { s.NotNil(s.d.preconfBlockServer.Start(port)) }()
defer func() { s.Nil(s.d.preconfBlockServer.Shutdown(s.d.ctx)) }()

url, err := url.Parse(fmt.Sprintf("http://localhost:%v", port))
s.Nil(err)

l2Head1, err := s.d.rpc.L2.HeaderByNumber(context.Background(), nil)
s.Nil(err)

s.Nil(s.d.ChainSyncer().BlobSyncer().ProcessL1Blocks(context.Background()))

// Propose valid L2 blocks to make the L2 fork into Pacaya fork.
for i := 0; i < int(s.RPCClient.PacayaClients.ForkHeight); i++ {
s.ProposeAndInsertValidBlock(s.p, s.d.ChainSyncer().BlobSyncer())
}

l2Head2, err := s.d.rpc.L2.HeaderByNumber(context.Background(), nil)
s.Nil(err)

l1Head1, err := s.d.rpc.L1.HeaderByNumber(context.Background(), nil)
s.Nil(err)

s.Greater(l2Head2.Number.Uint64(), l2Head1.Number.Uint64())

res, err := resty.New().R().Get(url.String() + "/healthz")
s.Nil(err)
s.True(res.IsSuccess())

// Try to insert one preconfirmation block
s.True(s.insertPreconfBlock(url, l1Head1, l2Head2.Number.Uint64()+1, l2Head2.GasLimit).IsSuccess())
l2Head3, err := s.d.rpc.L2.BlockByNumber(context.Background(), nil)
s.Nil(err)

s.Equal(2, len(l2Head3.Transactions()))

l1Origin, err := s.RPCClient.L2.L1OriginByID(context.Background(), new(big.Int).Add(l2Head2.Number, common.Big1))
s.Nil(err)
s.Equal(l2Head3.Number().Uint64(), l1Origin.BlockID.Uint64())
s.Equal(l2Head3.Hash(), l1Origin.L2BlockHash)
s.Equal(common.Hash{}, l1Origin.L1BlockHash)
s.True(l1Origin.IsPreconfBlock())

s.proposePreconfBatch([]*types.Block{l2Head3}, []*types.Header{l1Head1})

l2Head4, err := s.d.rpc.L2.BlockByNumber(context.Background(), nil)
s.Nil(err)
s.Equal(l2Head3.Number().Uint64(), l2Head4.Number().Uint64())
s.Equal(2, len(l2Head4.Transactions()))
}

func (s *DriverTestSuite) proposePreconfBatch(blocks []*types.Block, anchoredL1Blocks []*types.Header) {
var (
to = &s.p.TaikoL1Address
data []byte
blockParams []pacayaBindings.ITaikoInboxBlockParams
allTxs types.Transactions
)

s.NotZero(len(blocks))
s.Equal(len(blocks), len(anchoredL1Blocks))

for _, b := range blocks {
allTxs = append(allTxs, b.Transactions()...)
blockParams = append(blockParams, pacayaBindings.ITaikoInboxBlockParams{
NumTransactions: uint16(b.Transactions().Len()),
TimeShift: 0,
})
}

rlpEncoded, err := rlp.EncodeToBytes(allTxs)
s.Nil(err)
txListsBytes, err := utils.Compress(rlpEncoded)
s.Nil(err)

encodedParams, err := encoding.EncodeBatchParams(&encoding.BatchParams{
Coinbase: blocks[0].Coinbase(),
BlobParams: encoding.BlobParams{
ByteOffset: 0,
ByteSize: uint32(len(txListsBytes)),
},
Blocks: blockParams,
AnchorBlockId: anchoredL1Blocks[0].Number.Uint64(),
LastBlockTimestamp: blocks[len(blocks)-1].Time(),
})
s.Nil(err)

if s.p.ProverSetAddress != rpc.ZeroAddress {
to = &s.p.ProverSetAddress
data, err = encoding.ProverSetPacayaABI.Pack("proposeBatch", encodedParams, txListsBytes)
} else {
data, err = encoding.TaikoInboxABI.Pack("proposeBatch", encodedParams, txListsBytes)
}
s.Nil(err)
s.Nil(s.p.SendTx(context.Background(), &txmgr.TxCandidate{TxData: data, Blobs: nil, To: to}))
s.Nil(
backoff.Retry(func() error {
return s.d.ChainSyncer().BlobSyncer().ProcessL1Blocks(context.Background())
}, backoff.NewExponentialBackOff()))
}

func (s *DriverTestSuite) InitProposer() {
p := new(proposer.Proposer)

Expand Down
6 changes: 5 additions & 1 deletion packages/taiko-client/pkg/rpc/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,11 @@ func (c *Client) initForkHeightConfigs(ctx context.Context) error {
c.PacayaClients.ForkHeight = pacayaForkHeightDevnet
}

log.Info("Pacaya fork client fork height", "chainID", c.L2.ChainID.Uint64(), "forkHeight", c.PacayaClients.ForkHeight)
log.Info(
"Pacaya fork client fork height",
"chainID", c.L2.ChainID.Uint64(),
"forkHeight", c.PacayaClients.ForkHeight,
)

ontakeProtocolConfigs, err := c.OntakeClients.TaikoL1.GetConfig(&bind.CallOpts{Context: ctx})
if err != nil {
Expand Down
8 changes: 4 additions & 4 deletions packages/taiko-client/proposer/proposer.go
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ func (p *Proposer) ProposeTxListOntake(
return err
}

if err := p.sendTx(ctx, txCandidate); err != nil {
if err := p.SendTx(ctx, txCandidate); err != nil {
return err
}

Expand Down Expand Up @@ -450,7 +450,7 @@ func (p *Proposer) ProposeTxListPacaya(
return err
}

if err := p.sendTx(ctx, txCandidate); err != nil {
if err := p.SendTx(ctx, txCandidate); err != nil {
return err
}

Expand Down Expand Up @@ -480,8 +480,8 @@ func (p *Proposer) updateProposingTicker() {
p.proposingTimer = time.NewTimer(duration)
}

// sendTx is the internal function to send a transaction with a selected tx manager.
func (p *Proposer) sendTx(ctx context.Context, txCandidate *txmgr.TxCandidate) error {
// SendTx is the function to send a transaction with a selected tx manager.
func (p *Proposer) SendTx(ctx context.Context, txCandidate *txmgr.TxCandidate) error {
txMgr, isPrivate := p.txmgrSelector.Select()
receipt, err := txMgr.Send(ctx, *txCandidate)
if err != nil {
Expand Down
Loading