区块链中文技术社区

polygon cdk 跨链桥交易处理流程分析

数据产生

synchronizer/synchronizer.go

func (s *ClientSynchronizer) syncBlocks(lastBlockSynced *etherman.Block) (*etherman.Block, error) {
...
blocks, order, err := s.etherMan.GetRollupInfoByBlockRange(s.ctx, fromBlock, &toBlock)

etherMan.readEvents

func (etherMan *Client) GetRollupInfoByBlockRange(ctx context.Context, fromBlock uint64, toBlock *uint64) ([]Block, map[common.Hash][]Order, error) {
    // Filter query
    query := ethereum.FilterQuery{
        FromBlock: new(big.Int).SetUint64(fromBlock),
        Addresses: etherMan.SCAddresses,
        Topics:    [][]common.Hash{{updateGlobalExitRootSignatureHash, updateL1InfoTreeSignatureHash, depositEventSignatureHash, claimEventSignatureHash, oldClaimEventSignatureHash, newWrappedTokenEventSignatureHash, verifyBatchesTrustedAggregatorSignatureHash, rollupManagerVerifyBatchesSignatureHash}},
    }
    if toBlock != nil {
        query.ToBlock = new(big.Int).SetUint64(*toBlock)
    }
    blocks, blocksOrder, err := etherMan.readEvents(ctx, query)
    if err != nil {
        return nil, nil, err
    }
    return blocks, blocksOrder, nil
}
func (etherMan *Client) readEvents(ctx context.Context, query ethereum.FilterQuery) ([]Block, map[common.Hash][]Order, error) {
    logs, err := etherMan.EtherClient.FilterLogs(ctx, query)
    if err != nil {
        return nil, nil, err
    }
    var blocks []Block
    blocksOrder := make(map[common.Hash][]Order)
    for _, vLog := range logs {
        err := etherMan.processEvent(ctx, vLog, &blocks, &blocksOrder)
func (etherMan *Client) processEvent(ctx context.Context, vLog types.Log, blocks *[]Block, blocksOrder *map[common.Hash][]Order) error {
    switch vLog.Topics[0] {
    case updateGlobalExitRootSignatureHash:
        return etherMan.updateGlobalExitRootEvent(ctx, vLog, blocks, blocksOrder)
updateGlobalExitRootSignatureHash              = crypto.Keccak256Hash([]byte("UpdateGlobalExitRoot(bytes32,bytes32)"))
func (etherMan *Client) updateGlobalExitRootEvent(ctx context.Context, vLog types.Log, blocks *[]Block, blocksOrder *map[common.Hash][]Order) error {
    etherMan.logger.Debug("UpdateGlobalExitRoot event detected. Processing...")
    return etherMan.processUpdateGlobalExitRootEvent(ctx, vLog.Topics[1], vLog.Topics[2], vLog, blocks, blocksOrder)
}
func (etherMan *Client) processUpdateGlobalExitRootEvent(ctx context.Context, mainnetExitRoot, rollupExitRoot common.Hash, vLog types.Log, blocks *[]Block, blocksOrder *map[common.Hash][]Order) error {
    var gExitRoot GlobalExitRoot
    gExitRoot.ExitRoots = make([]common.Hash, 0)
    gExitRoot.ExitRoots = append(gExitRoot.ExitRoots, mainnetExitRoot)
    gExitRoot.ExitRoots = append(gExitRoot.ExitRoots, rollupExitRoot)
    gExitRoot.GlobalExitRoot = hash(mainnetExitRoot, rollupExitRoot)
    gExitRoot.BlockNumber = vLog.BlockNumber

    if len(*blocks) == 0 || ((*blocks)[len(*blocks)-1].BlockHash != vLog.BlockHash || (*blocks)[len(*blocks)-1].BlockNumber != vLog.BlockNumber) {
        fullBlock, err := etherMan.EtherClient.HeaderByHash(ctx, vLog.BlockHash)
        if err != nil {
            return fmt.Errorf("error getting hashParent. BlockNumber: %d. Error: %v", vLog.BlockNumber, err)
        }
        t := time.Unix(int64(fullBlock.Time), 0)
        block := prepareBlock(vLog, t, fullBlock)
        block.GlobalExitRoots = append(block.GlobalExitRoots, gExitRoot)
        *blocks = append(*blocks, block)
    } else if (*blocks)[len(*blocks)-1].BlockHash == vLog.BlockHash && (*blocks)[len(*blocks)-1].BlockNumber == vLog.BlockNumber {
        (*blocks)[len(*blocks)-1].GlobalExitRoots = append((*blocks)[len(*blocks)-1].GlobalExitRoots, gExitRoot)
    } else {
        etherMan.logger.Error("Error processing UpdateGlobalExitRoot event. BlockHash:", vLog.BlockHash, ". BlockNumber: ", vLog.BlockNumber)
        return fmt.Errorf("error processing UpdateGlobalExitRoot event")
    }
    or := Order{
        Name: GlobalExitRootsOrder,
        Pos:  len((*blocks)[len(*blocks)-1].GlobalExitRoots) - 1,
    }
    (*blocksOrder)[(*blocks)[len(*blocks)-1].BlockHash] = append((*blocksOrder)[(*blocks)[len(*blocks)-1].BlockHash], or)
    return nil
}
GlobalExitRootsOrder EventOrder = "GlobalExitRoot"
func (s *ClientSynchronizer) syncBlocks(lastBlockSynced *etherman.Block) (*etherman.Block, error) {
...
err = s.processBlockRange(blocks, order)
func (s *ClientSynchronizer) processBlockRange(blocks []etherman.Block, order map[common.Hash][]etherman.Order) error {
    ...
    for _, element := range order[blocks[i].BlockHash] {
            switch element.Name {
            case etherman.GlobalExitRootsOrder:
                isNewGer = true
                err = s.processGlobalExitRoot(blocks[i].GlobalExitRoots[element.Pos], blockID, dbTx)
func (s *ClientSynchronizer) processGlobalExitRoot(globalExitRoot etherman.GlobalExitRoot, blockID uint64, dbTx pgx.Tx) error {
    // Store GlobalExitRoot
    globalExitRoot.BlockID = blockID
    err := s.storage.AddGlobalExitRoot(s.ctx, &globalExitRoot, dbTx)
func (p *PostgresStorage) AddGlobalExitRoot(ctx context.Context, exitRoot *etherman.GlobalExitRoot, dbTx pgx.Tx) error {
    const addExitRootSQL = "INSERT INTO sync.exit_root (block_id, global_exit_root, exit_roots) VALUES ($1, $2, $3)"
    e := p.getExecQuerier(dbTx)
    _, err := e.Exec(ctx, addExitRootSQL, exitRoot.BlockID, exitRoot.GlobalExitRoot, pq.Array([][]byte{exitRoot.ExitRoots[0][:], exitRoot.ExitRoots[1][:]}))
    return err
}

数据消费

var chsExitRootEvent []chan *etherman.GlobalExitRoot
    var chsSyncedL2 []chan uint
    for i, l2EthermanClient := range l2Ethermans {
        log.Debug("trusted sequencer URL ", c.Etherman.L2URLs[i])
        zkEVMClient := client.NewClient(c.Etherman.L2URLs[i])
        chExitRootEventL2 := make(chan *etherman.GlobalExitRoot)
        chSyncedL2 := make(chan uint)
        chsExitRootEvent = append(chsExitRootEvent, chExitRootEventL2)
        chsSyncedL2 = append(chsSyncedL2, chSyncedL2)
        go runSynchronizer(ctx.Context, 0, bridgeController, l2EthermanClient, c.Synchronizer, storage, zkEVMClient, chExitRootEventL2, nil, chSyncedL2, []uint{})
    }
func runSynchronizer(ctx context.Context, genBlockNumber uint64, brdigeCtrl *bridgectrl.BridgeController, etherman *etherman.Client, cfg synchronizer.Config, storage db.Storage, zkEVMClient *client.Client, chExitRootEventL2 chan *etherman.GlobalExitRoot, chsExitRootEvent []chan *etherman.GlobalExitRoot, chSynced chan uint, allNetworkIDs []uint) {
    sy, err := synchronizer.NewSynchronizer(ctx, storage, brdigeCtrl, etherman, zkEVMClient, genBlockNumber, chExitRootEventL2, chsExitRootEvent, chSynced, cfg, allNetworkIDs)
func (s *ClientSynchronizer) processBlockRange(blocks []etherman.Block, order map[common.Hash][]etherman.Order) error {
    var isNewGer bool
    for i := range blocks {
    ...
    for _, element := range order[blocks[i].BlockHash] {
            switch element.Name {
            case etherman.GlobalExitRootsOrder:
                isNewGer = true
                err = s.processGlobalExitRoot(blocks[i].GlobalExitRoots[element.Pos], blockID, dbTx)
    ...
    if isNewGer {
        // Send latest GER stored to claimTxManager
        ger, err := s.storage.GetLatestL1SyncedExitRoot(s.ctx, nil)
        if err != nil {
            log.Errorf("networkID: %d, error getting latest GER stored on database. Error: %v", s.networkID, err)
            return err
        }
        if s.l1RollupExitRoot != ger.ExitRoots[1] {
            log.Debugf("Updating ger: %+v", ger)
            s.l1RollupExitRoot = ger.ExitRoots[1]
            for _, ch := range s.chsExitRootEvent {
                ch <- ger
            }
        }
    }
func (s *ClientSynchronizer) processGlobalExitRoot(globalExitRoot etherman.GlobalExitRoot, blockID uint64, dbTx pgx.Tx) error {
    // Store GlobalExitRoot
    globalExitRoot.BlockID = blockID
    err := s.storage.AddGlobalExitRoot(s.ctx, &globalExitRoot, dbTx)
func (p *PostgresStorage) GetLatestL1SyncedExitRoot(ctx context.Context, dbTx pgx.Tx) (*etherman.GlobalExitRoot, error) {
    var (
        ger       etherman.GlobalExitRoot
        exitRoots [][]byte
    )
    const getLatestL1SyncedExitRootSQL = "SELECT block_id, global_exit_root, exit_roots FROM sync.exit_root WHERE block_id > 0 AND network_id = 0 ORDER BY id DESC LIMIT 1"
    err := p.getExecQuerier(dbTx).QueryRow(ctx, getLatestL1SyncedExitRootSQL).Scan(&ger.BlockID, &ger.GlobalExitRoot, pq.Array(&exitRoots))
    if err != nil {
        if errors.Is(err, pgx.ErrNoRows) {
            return &ger, gerror.ErrStorageNotFound
        }
        return nil, err
    }
    ger.ExitRoots = []common.Hash{common.BytesToHash(exitRoots[0]), common.BytesToHash(exitRoots[1])}
    return &ger, nil
}
func start(ctx *cli.Context) error {
    if c.ClaimTxManager.Enabled {
        for i := 0; i < len(c.Etherman.L2URLs); i++ {
            ...
            claimTxManager, err := claimtxman.NewClaimTxManager(ctx, c.ClaimTxManager, chsExitRootEvent[i], chsSyncedL2[i],
                c.Etherman.L2URLs[i], networkIDs[i+1], c.NetworkConfig.L2PolygonBridgeAddresses[i], bridgeService, storage, rollupID, l2Ethermans[i], nonceCache, auth)
func (tm *ClaimTxManager) Start() {
        ...
        case ger = <-tm.chExitRootEvent:
            if tm.synced {
                log.Debugf("RollupID: %d UpdateDepositsStatus for ger: %s", tm.rollupID, ger.GlobalExitRoot.String())
                if tm.cfg.GroupingClaims.Enabled {
                    log.Debugf("rollupID: %d, Ger value updated and ready to be processed...", tm.rollupID)
                    continue
                }
                go func() {
                    err := tm.updateDepositsStatus(ger)
                    if err != nil {
                        log.Errorf("rollupID: %d, failed to update deposits status: %v", tm.rollupID, err)
                    }
                }()
func (tm *ClaimTxManager) updateDepositsStatus(ger *etherman.GlobalExitRoot) error {
    dbTx, err := tm.storage.BeginDBTransaction(tm.ctx)
    if err != nil {
        return err
    }
    err = tm.processDepositStatus(ger, dbTx)
func (tm *ClaimTxManager) processDepositStatus(ger *etherman.GlobalExitRoot, dbTx pgx.Tx) error {
    if ger.BlockID != 0 { // L2 exit root is updated
...
    } else { // L1 exit root is updated in the trusted state
        log.Infof("RollupID: %d, Mainnet exitroot %v is updated", tm.rollupID, ger.ExitRoots[0])
        deposits, err := tm.storage.UpdateL1DepositsStatus(tm.ctx, ger.ExitRoots[0][:], tm.l2NetworkID, dbTx)
func (p *PostgresStorage) UpdateL1DepositsStatus(ctx context.Context, exitRoot []byte, destinationNetwork uint, dbTx pgx.Tx) ([]*etherman.Deposit, error) {
    const updateDepositsStatusSQL = `UPDATE sync.deposit SET ready_for_claim = true 

合约分析

PolygonZkEVMGlobalExitRoot.sol

function updateExitRoot(bytes32 newRoot) external {
        ...
        // If it already exists, do not modify the timestamp
        if (globalExitRootMap[newGlobalExitRoot] == 0) {
            globalExitRootMap[newGlobalExitRoot] = block.timestamp;
            emit UpdateGlobalExitRoot(
                cacheLastMainnetExitRoot,
                cacheLastRollupExitRoot
            );
        }
    }

PolygonZkEVMGlobalExitRootV2.sol

function updateExitRoot(bytes32 newRoot) external {
        ...
            emit UpdateL1InfoTree(
                cacheLastMainnetExitRoot,
                cacheLastRollupExitRoot
            );

            emit UpdateL1InfoTreeV2(
                currentL1InfoRoot,
                uint32(depositCount),
                lastBlockHash,
                currentTimestmap
            );
        }
    }
func (etherMan *Client) processEvent(ctx context.Context, vLog types.Log, blocks *[]Block, blocksOrder *map[common.Hash][]Order) error {
    switch vLog.Topics[0] {
...
    case updateL1InfoTreeSignatureHash:
        return etherMan.updateL1InfoTreeEvent(ctx, vLog, blocks, blocksOrder)
func (etherMan *Client) updateL1InfoTreeEvent(ctx context.Context, vLog types.Log, blocks *[]Block, blocksOrder *map[common.Hash][]Order) error {
    etherMan.logger.Debug("UpdateL1InfoTree event detected")
    globalExitRoot, err := etherMan.PolygonZkEVMGlobalExitRoot.ParseUpdateL1InfoTree(vLog)
    if err != nil {
        return err
    }
    return etherMan.processUpdateGlobalExitRootEvent(ctx, globalExitRoot.MainnetExitRoot, globalExitRoot.RollupExitRoot, vLog, blocks, blocksOrder)
}
if isNewGer {
        // Send latest GER stored to claimTxManager
        ger, err := s.storage.GetLatestL1SyncedExitRoot(s.ctx, nil)
        if err != nil {
            log.Errorf("networkID: %d, error getting latest GER stored on database. Error: %v", s.networkID, err)
            return err
        }
        if s.l1RollupExitRoot != ger.ExitRoots[1] {
            log.Debugf("Updating ger: %+v", ger)
            s.l1RollupExitRoot = ger.ExitRoots[1]
            for _, ch := range s.chsExitRootEvent {
                ch <- ger
            }
        }
    }
func (p *PostgresStorage) GetLatestL1SyncedExitRoot(ctx context.Context, dbTx pgx.Tx) (*etherman.GlobalExitRoot, error) {
    var (
        ger       etherman.GlobalExitRoot
        exitRoots [][]byte
    )
    const getLatestL1SyncedExitRootSQL = "SELECT block_id, global_exit_root, exit_roots FROM sync.exit_root WHERE block_id > 0 AND network_id = 0 ORDER BY id DESC LIMIT 1"
    err := p.getExecQuerier(dbTx).QueryRow(ctx, getLatestL1SyncedExitRootSQL).Scan(&ger.BlockID, &ger.GlobalExitRoot, pq.Array(&exitRoots))
    if err != nil {
        if errors.Is(err, pgx.ErrNoRows) {
            return &ger, gerror.ErrStorageNotFound
        }
        return nil, err
    }
    ger.ExitRoots = []common.Hash{common.BytesToHash(exitRoots[0]), common.BytesToHash(exitRoots[1])}
    return &ger, nil
}

// TODO 继续分析

总和分析

  1. PolygonZkEVMGlobalExitRoot合约升级到V2后,UpdateGlobalExitRoot事件由UpdateL1InfoTree代替,但是桥合约内部是统一处理的,不存在兼容性
  2. 数据库查看对应数据
    SELECT block_id, global_exit_root, exit_roots FROM sync.exit_root;

    block_id | global_exit_root| exit_roots

    1 | \x304fb89608cfb05e5eac3b9e7c70df5821e03b6f8166baf4192f4d921c44f651 | {"\\x76ab2578418da24f3754ecfdef1de5ff8631ca577f998799287eee91b4aace2c","\\x0000000000000000000000000000000000000000000000000000000000000000"}
    2 | \x8c9a2fea84f58dc994dac422ab7ee94238643f976de700a25ec3c5701b5acf32 | {"\\xcc7402af30b35a4ee3d5b793cfed1678ae8529e7ffa79e75ae2e4baaa890df21","\\x0000000000000000000000000000000000000000000000000000000000000000"}
    0 | \x8c9a2fea84f58dc994dac422ab7ee94238643f976de700a25ec3c5701b5acf32 | {"\\xcc7402af30b35a4ee3d5b793cfed1678ae8529e7ffa79e75ae2e4baaa890df21","\\x0000000000000000000000000000000000000000000000000000000000000000"}

因RPC限速导致sequence-sender异常退出

问题

因RPC限速导致sequence-sender异常退出

2024-11-15T11:49:59.657Z        ERROR   sync/evmdownloader.go:248       error calling FilterLogs to eth client: 429 Too Many Requests: {"id":9,"jsonrpc":"2.0","error":{"code":-32005,"message":"rate limit exceeded"}}{"pid": 40, "version": "v0.4.0-beta5", "syncer": "l1infotreesync"}
github.com/0xPolygon/cdk/sync.(*EVMDownloaderImplementation).GetLogs
        /go/src/github.com/0xPolygon/cdk/sync/evmdownloader.go:248
github.com/0xPolygon/cdk/sync.(*EVMDownloaderImplementation).GetEventsByBlockRange
        /go/src/github.com/0xPolygon/cdk/sync/evmdownloader.go:184
github.com/0xPolygon/cdk/sync.(*EVMDownloader).Download
        /go/src/github.com/0xPolygon/cdk/sync/evmdownloader.go:97
2024/11/15 11:49:59 getLogs failed too many times (0)

相关代码

type RetryHandler struct {
    RetryAfterErrorPeriod      time.Duration
    MaxRetryAttemptsAfterError int
}

func (h *RetryHandler) Handle(funcName string, attempts int) {
    if h.MaxRetryAttemptsAfterError > -1 && attempts >= h.MaxRetryAttemptsAfterError {
        log.Fatalf(
            "%s failed too many times (%d)",
            funcName, h.MaxRetryAttemptsAfterError,
        )
    }
    time.Sleep(h.RetryAfterErrorPeriod)
}

解决

在sequence-sender 配置->L1InfoTreeSync下增加两个配置

  • MaxRetryAttemptsAfterError 总共重试多少次后,异常退出,可以设置一个较大值
  • RetryAfterErrorPeriod:每次重试的间隔时间

error getting sequences: error no leaves on L1InfoTree yet and GetInitL1InfoRootMap

错误

启动sequence-sender时报以下错误

2024-11-15T11:11:46.117Z        ERROR   sequencesender/sequencesender.go:312    error getting sequences: error no leaves on L1InfoTree yet and GetInitL1InfoRootMap fails: %!w(<nil>)   {"pid": 39, "version": "v0.4.0-beta5", "module": "sequence-sender"}
github.com/0xPolygon/cdk/sequencesender.(*SequenceSender).tryToSendSequence
        /go/src/github.com/0xPolygon/cdk/sequencesender/sequencesender.go:312
github.com/0xPolygon/cdk/sequencesender.(*SequenceSender).sequenceSending
        /go/src/github.com/0xPolygon/cdk/sequencesender/sequencesender.go:243

相关代码

// Returns CounterL1InfoRoot to use for this batch
func (t *TxBuilderBananaBase) GetCounterL1InfoRoot(ctx context.Context, highestL1IndexInBatch uint32) (uint32, error) {
    header, err := t.ethClient.HeaderByNumber(ctx, t.blockFinality)
    if err != nil {
        return 0, fmt.Errorf("error calling HeaderByNumber, with block finality %d: %w", t.blockFinality.Int64(), err)
    }
    var resL1InfoCounter uint32

    info, err := t.l1InfoTree.GetLatestInfoUntilBlock(ctx, header.Number.Uint64())
    if err == nil {
        resL1InfoCounter = info.L1InfoTreeIndex + 1
    }
    if errors.Is(err, l1infotreesync.ErrNotFound) {
        // There are no L1 Info tree leaves yet, so we can try to use L1InfoRootMap event
        l1infotreeInitial, err := t.l1InfoTree.GetInitL1InfoRootMap(ctx)
        if l1infotreeInitial == nil || err != nil {
            return 0, fmt.Errorf("error no leaves on L1InfoTree yet and GetInitL1InfoRootMap fails: %w", err)
        }
        // We use this leaf as first one
        resL1InfoCounter = l1infotreeInitial.LeafCount
    } else if err != nil {
        return 0, fmt.Errorf("error calling GetLatestInfoUntilBlock with block num %d: %w", header.Number.Uint64(), err)
    }

分析

l1InfoTree.GetInitL1InfoRootMap 没有获取到数据
GetInitL1InfoRootMap 通过事件InitL1InfoRootMap进行写入的

if event.InitL1InfoRootMap != nil {
            log.Debugf("handle InitL1InfoRootMap event %s", event.InitL1InfoRootMap.String())
            err = processEventInitL1InfoRootMap(tx, block.Num, event.InitL1InfoRootMap)
            if err != nil {
                err = fmt.Errorf("initL1InfoRootMap. Err: %w", err)
                log.Errorf("error processing InitL1InfoRootMap: %v", err)
                return err
            }
        }

对应合约PolygonZkEVMGlobalExitRootV2.sol->emit InitL1InfoRootMap

 function initialize() external virtual initializer {
        // Get the current historic root
        bytes32 currentL1InfoRoot = getRoot();

        // Store L1InfoRoot
        l1InfoRootMap[uint32(depositCount)] = currentL1InfoRoot;

        emit InitL1InfoRootMap(uint32(depositCount), currentL1InfoRoot);
    }

继续排查,看链是否代码没有执行对应逻辑
l1infotreesync/processor.go

func (p *processor) ProcessBlock(ctx context.Context, block sync.Block) error {
    ...
        if event.InitL1InfoRootMap != nil {
            log.Debugf("handle InitL1InfoRootMap event %s", event.InitL1InfoRootMap.String())
            err = processEventInitL1InfoRootMap(tx, block.Num, event.InitL1InfoRootMap)
            if err != nil {
                err = fmt.Errorf("initL1InfoRootMap. Err: %w", err)
                log.Errorf("error processing InitL1InfoRootMap: %v", err)
                return err
            }
        }
func (d *EVMDriver) handleNewBlock(ctx context.Context, b EVMBlock) {
    ...
    err := d.processor.ProcessBlock(ctx, blockToProcess)
2024-11-16T01:17:02.244Z        DEBUG   sync/evmdriver.go:100   handleNewBlock blockNum: 7085616 blockHash: 0x72c30608c656bfd164e1e5836db12d6b36ad2f7ddbd5e26557ea18fcdce98d94  {"pid": 40, "version": "v0.4.0-beta5", "syncer": "l1infotreesync"}
2024-11-16T01:17:02.244Z        INFO    l1infotreesync/processor.go:343 block 7085616 processed with 0 events   {"pid": 40, "version": "v0.4.0-beta5"}

执行逻辑中已经包含 event.InitL1InfoRootMap

继续排查

排查两个角度

  1. 合约中并未发出
  2. 区块高度有错误
    由于事件是由合约PolygonZkEVMGlobalExitRootV2.sol发出,对应的合约地址为deploy_output.json->polygonZkEVMGlobalExitRootAddress
    查看当前地址
    https://sepolia.etherscan.io/tx/0xc3b16bdaa7054689230e976e20badcb65c92ad2a623ea89b1b33147a1fc0f227#eventlog

    高度:7085224
    合约event.InitL1InfoRootMap已发出,排除问题1

继续看下配置的高度deploy_output.json->deploymentRollupManagerBlockNumber
https://sepolia.etherscan.io/tx/0x03f41442db2e20f2551436df6ec607be307c89e7b05fe32fc462fceb225ce24a
高度:7085226

问题汇总

当前高度没有包含PolygonZkEVMGlobalExitRootV2->initialize 高度,所以导致事件event.InitL1InfoRootMap没有扫描到,从而导致GetInitL1InfoRootMap数据没有本地存储,最终导致sequence-sender报错

解决方式

查询deploy_output.json->polygonZkEVMGlobalExitRootAddress合约地址交易对应的高度,并更新到sequence-sender配置
L1InfoTreeSync->InitialBlock

https://sepolia.etherscan.io/address/0xEEc7988853B40B65FaBB3E9A3393E093D5710515

polygon cdk fork12各服务版本对应关系

fork版本 服务名称 tag 官方镜像
fork12 zkevm-contracts v8.0.0-fork.12
zkevm-prover-stateless-executor v8.0.0-RC14-fork.12 hermeznetwork/zkevm-prover:v8.0.0-RC14-fork.12
zkevm-prover-state-executor v8.0.0-RC14-fork.12 hermeznetwork/zkevm-prover:v8.0.0-RC14-fork.12
cdk-erigon-sequencer v2.1.2 hermeznetwork/cdk-erigon:v2.1.2
cdk-erigon-rpc v2.1.2 hermeznetwork/cdk-erigon:v2.1.2
zkevm-pool-manager v0.1.2 hermeznetwork/zkevm-pool-manager:v0.1.2
Sequence sender&Aggregator v0.4.0-beta5 ghcr.io/0xpolygon/cdk:0.4.0-beta5
cdk-data-availability v0.0.10 0xpolygon/cdk-data-availability:0.0.10
bridge-service v0.6.0-RC1 hermeznetwork/zkevm-bridge-service:v0.6.0-RC1

调研polygon cdk-fork12是否支持在polygon pos测试网amoy部署

背景

调研polygon cdk-fork12是否支持在polygon pos测试网amoy部署

前置结论

结论:polygon cdk-fork12依赖于以太坊PoS状态检查,polygon pos测试网amoy RPC未实现该逻辑导致不兼容,无法支持部署polygon网络

概述

在推荐配置下,da,sequencer,sync,pool-manager,bridge 各个核心服务正常运行,交易正常处理
但sequence-sender运行报错,跟进代码,由于交易状态检查逻辑中,会依次检查各个状态的过度:LatestBlock->SafeBlock->PendingBlock->FinalizedBlock,由于polygon pos测试网amoy没有像以太坊PoS完整实现,所以导致报错

2024-11-14T12:21:48.112Z        ERROR   l1_check_block/l1_block_by_name.go:171  checkL1block:: Error getting L1 block %!d(string=safe/0). err: safe block not found     {"pid": 40}
github.com/0xPolygonHermez/zkevm-synchronizer-l1/synchronizer/l1_check_block.(*L1BlockNumberByNameFetch).BlockNumber
        /go/pkg/mod/github.com/0x!polygon!hermez/zkevm-synchronizer-l1@v1.0.5/synchronizer/l1_check_block/l1_block_by_name.go:171
github.com/0xPolygon/zkevm-ethtx-manager/ethtxmanager.(*Client).waitMinedTxToBeSafe
        /go/pkg/mod/github.com/0x!polygon/zkevm-ethtx-manager@v0.2.1/ethtxmanager/ethtxmanager.go:525
github.com/0xPolygon/zkevm-ethtx-manager/ethtxmanager.(*Client).Start
        /go/pkg/mod/github.com/0x!polygon/zkevm-ethtx-manager@v0.2.1/ethtxmanager/ethtxmanager.go:458
2024-11-14T12:21:48.112Z        ERROR   ethtxmanager/ethtxmanager.go:927        failed to wait safe tx to be finalized: failed to get safe block number: safe block not found%!(EXTRA string=
/go/pkg/mod/github.com/0x!polygon/zkevm-ethtx-manager@v0.2.1/log/log.go:140 github.com/0xPolygon/zkevm-ethtx-manager/log.appendStackTraceMaybeArgs()
/go/pkg/mod/github.com/0x!polygon/zkevm-ethtx-manager@v0.2.1/log/log.go:249 github.com/0xPolygon/zkevm-ethtx-manager/log.Errorf()
/go/pkg/mod/github.com/0x!polygon/zkevm-ethtx-manager@v0.2.1/ethtxmanager/ethtxmanager.go:927 github.com/0xPolygon/zkevm-ethtx-manager/ethtxmanager.(*Client).logErrorAndWait()
/go/pkg/mod/github.com/0x!polygon/zkevm-ethtx-manager@v0.2.1/ethtxmanager/ethtxmanager.go:460 github.com/0xPolygon/zkevm-ethtx-manager/ethtxmanager.(*Client).Start()
// BlockFinality indicates the status of the blocks that will be queried in order to sync
    BlockFinality string `jsonschema:"enum=LatestBlock, enum=SafeBlock, enum=PendingBlock, enum=FinalizedBlock, enum=EarliestBlock" mapstructure:"BlockFinality"` //nolint:lll